diff --git a/GLOSSARY_LINKING_GUIDE.md b/GLOSSARY_LINKING_GUIDE.md new file mode 100644 index 0000000..dbb3973 --- /dev/null +++ b/GLOSSARY_LINKING_GUIDE.md @@ -0,0 +1,515 @@ +# Glossary Link Automation Guide + +## Overview + +This guide explains how to automatically add glossary links throughout the Robot Framework RFCP Syllabus documentation. The automation tool identifies glossary terms in documentation files and creates hyperlinks to the interactive glossary page. + +## What This Tool Does + +The glossary linker automatically transforms terms into clickable links: + +**Before:** +```markdown +The Variable Number of Positional Arguments is marked with a single asterisk. +``` + +**After:** +```markdown +The [Variable Number of Positional Arguments](../glossary#variable-number-of-positional-arguments) is marked with a single asterisk. +``` + +The tool: +- ✅ Links 80+ glossary terms automatically +- ✅ Uses relative paths (works in both local dev and production) +- ✅ Preserves code blocks and headings +- ✅ Only links terms in body content (keeps navigation clean) +- ✅ Handles term aliases (e.g., "kwargs" → "Free Named Argument") + +## Prerequisites + +- Python 3.7 or higher +- Git +- Node.js and npm (for testing) +- Write access to the repository + +## Installation + +### 1. Locate the Tool + +The glossary linker tool is located in the repository at: +``` +tools/glossary_linker.py +``` + +If you're setting this up for the first time, the tool should already be in the repository. If not, contact the repository maintainers. + +### 2. Verify Python Installation + +```bash +python3 --version +``` + +You should see Python 3.7 or higher. + +## Usage Instructions + +### Step 1: Navigate to Repository Root + +```bash +cd /path/to/robotframework-RFCP-syllabus +``` + +### Step 2: Create a Feature Branch + +Always work in a feature branch: + +```bash +git checkout -b feature/update-glossary-links +``` + +### Step 3: Run in Test Mode (DRY RUN) + +**IMPORTANT: Always run in dry-run mode first!** + +```bash +python3 tools/glossary_linker.py website/docs --dry-run +``` + +This shows you what would be changed without modifying any files. + +**Review the output:** +- Check the number of files that will be modified +- Verify which terms will be linked +- Ensure no unexpected changes + +Example output: +``` +Processing: website/docs +Dry run: True +Relative paths: True + +============================================================ +SUMMARY +============================================================ +Total files: 45 +Modified: 28 +Terms linked: 234 + +============================================================ +DETAILS +============================================================ + +chapter-02/keyword_interface.md + Terms: 15 + - Variable Number of Positional Arguments: 5x + - Named-Only Argument: 3x + - Free Named Argument: 2x +``` + +### Step 4: Apply Changes + +Once you're satisfied with the dry-run output: + +```bash +python3 tools/glossary_linker.py website/docs +``` + +This will: +- Modify markdown files in `website/docs/` +- Add glossary links to terms in body content +- Preserve headings, code blocks, and frontmatter +- Create a statistics file: `stats.json` + +### Step 5: Review Changes + +Use git to review what was changed: + +```bash +# See all changed files +git status + +# View specific changes +git diff website/docs/chapter-02/keyword_interface.md + +# View summary of changes +git diff --stat website/docs/ +``` + +**What to check:** +- ✅ Links use relative paths: `../glossary#term` +- ✅ Headings are NOT linked: `## 2.5 Keyword Interface` (clean) +- ✅ Body content IS linked: `The [Keyword Interface](../glossary#...)...` +- ✅ Code blocks are unchanged + +### Step 6: Test Locally + +Build and run the documentation locally: + +```bash +cd website +npm install # First time only +npm start +``` + +This opens the documentation at `http://localhost:3000` + +**Test the links:** +1. Navigate to Chapter 2, Section 2.5 +2. Click on a glossary term (e.g., "Variable Number of Positional Arguments") +3. Verify you're taken to the glossary page +4. Verify the correct term is highlighted +5. Test 3-5 different links across different chapters + +**Check navigation:** +1. Look at the left sidebar - terms should NOT be linked +2. Look at Previous/Next buttons - terms should NOT be linked +3. Both should show clean text without `[...]` brackets + +### Step 7: Build for Production + +Test the production build: + +```bash +npm run build +npm run serve +``` + +Navigate to `http://localhost:3000` and verify links work in the production build. + +### Step 8: Commit Changes + +```bash +cd .. # Back to repository root + +# Stage all changes +git add website/docs/ + +# Commit with descriptive message +git commit -m "Add glossary links to documentation + +- Automatically linked 80+ glossary terms +- Links use relative paths for local dev compatibility +- Covers argument types, variables, control structures, core concepts +- Tested locally and in production build +- All links verified working correctly" +``` + +### Step 9: Push and Create Pull Request + +```bash +# Push your branch +git push origin feature/update-glossary-links +``` + +Then create a pull request on GitHub with the following information: + +**PR Title:** Add glossary links to documentation + +**PR Description:** +```markdown +## Summary +Automatically added glossary links throughout the documentation using the glossary linker tool. + +## Changes +- Linked 80+ glossary terms across ~28 files +- Terms include: argument types, variables, control structures, core RF concepts +- Links use relative paths (works in both local dev and production) + +## Testing +- [x] Ran in dry-run mode and reviewed output +- [x] Tested locally with `npm start` +- [x] Verified glossary links work correctly +- [x] Checked sidebar and navigation are clean (no links) +- [x] Tested production build with `npm run build` +- [x] Reviewed git diff for all changed files + +## Statistics +- Total files processed: [X] +- Files modified: [X] +- Terms linked: [X] occurrences + +## Screenshots +[Optional: Add screenshots showing working links] +``` + +## Understanding the Tool + +### How It Works + +The tool processes markdown files in several steps: + +1. **Extracts frontmatter** - YAML metadata at the top of files +2. **Identifies sections** - Separates headings, code blocks, and content +3. **Applies patterns** - Matches glossary terms in content only +4. **Creates links** - Generates relative links to glossary +5. **Preserves structure** - Keeps headings and code blocks unchanged + +### What Gets Linked + +The tool links these types of terms: + +**Argument Types:** +- Mandatory Argument, Optional Argument +- Positional Argument, Named Argument +- Embedded Argument +- Positional or Named Argument +- Variable Number of Positional Arguments (*args, *varargs) +- Named-Only Argument +- Free Named Argument (kwargs, **kwargs) + +**Variables:** +- Variable, Scalar Variable, List Variable +- Variable Scope +- Global Variable, Suite Variable, Local Variable +- Built-In Variables + +**Control Structures:** +- Control Structure +- FOR Loop, WHILE Loop + +**Core Concepts:** +- Keyword, User Keyword, Keyword Library +- Suite, Test Case, Task +- Resource File +- Keyword Interface, Argument Interface + +And 50+ more terms... + +### What Gets Excluded + +The tool does NOT link terms in: + +- ❌ Markdown headings (`#`, `##`, `###`, etc.) +- ❌ YAML frontmatter (`---...---`) +- ❌ Code blocks (` ``` ` or `` ` ``) +- ❌ Existing links +- ❌ HTML `` tags + +This ensures: +- Sidebar navigation stays clean +- Previous/Next navigation stays clean +- Code examples remain unchanged + +### Link Format + +Links are generated as relative paths: + +| File Location | Generated Link | +|--------------|----------------| +| `docs/overview.md` | `./glossary#term` | +| `docs/chapter-02/page.md` | `../glossary#term` | +| `docs/chapter-02/sub/page.md` | `../../glossary#term` | + +This ensures links work in: +- ✅ Local development (`npm start`) +- ✅ Production builds +- ✅ Deployed sites + +## Troubleshooting + +### Issue: Terms Not Being Linked + +**Possible causes:** +1. Term is in a heading +2. Term is in a code block +3. Term is already linked +4. Term is not in the glossary term list + +**Solution:** +- Verify the term exists in `GLOSSARY_DATA` in the script +- Check that it's in body content, not a heading +- Ensure it's not in a `` ``` `` code block + +### Issue: Links Show in Sidebar + +**Symptom:** Sidebar shows `[Keyword Interface](...)` instead of clean text + +**Cause:** Terms were linked in headings + +**Solution:** This shouldn't happen with the current tool. If it does: +1. Revert changes: `git checkout website/docs/` +2. Ensure you're using the latest version of the tool +3. Re-run the tool + +### Issue: Links Don't Work Locally + +**Symptom:** Clicking links shows "Page Not Found" + +**Cause:** Using absolute paths instead of relative paths + +**Solution:** The current tool uses relative paths by default. Verify links in the markdown look like: +- ✅ `../glossary#term` (relative - correct) +- ❌ `/robotframework-RFCP-syllabus/docs/glossary#term` (absolute - incorrect) + +### Issue: Code Examples Have Links + +**Symptom:** Links appear inside code blocks + +**Cause:** Code block not properly detected + +**Solution:** +1. Ensure code blocks use proper markdown (` ``` `) +2. Check for unclosed code blocks +3. Report the issue if it persists + +## Updating the Tool + +### When to Update + +Update the glossary linker when: +- New glossary terms are added +- Term definitions change +- Aliases need to be updated + +### How to Update + +Edit `tools/glossary_linker.py` and modify the `GLOSSARY_DATA` list: + +```python +GLOSSARY_DATA = [ + { + 'term': 'New Term Name', + 'definition': 'Brief definition', + 'abbreviation': 'NTN', # Optional + 'aliases': ['Alternative Name', 'Another Alias'] # Optional + }, + # ... existing terms ... +] +``` + +Then commit the updated tool: + +```bash +git add tools/glossary_linker.py +git commit -m "Update glossary linker with new terms" +``` + +### Testing Updates + +After updating the tool: + +1. Run on a single file first: + ```bash + python3 tools/glossary_linker.py website/docs/chapter-02 --dry-run + ``` + +2. Verify the new terms are detected + +3. Apply to full documentation: + ```bash + python3 tools/glossary_linker.py website/docs + ``` + +## Maintenance + +### Regular Updates + +Run the glossary linker periodically: +- After adding new documentation chapters +- After updating existing content +- Quarterly maintenance runs + +### Re-running the Tool + +The tool is **idempotent** - running it multiple times on the same content will: +- ✅ Not create duplicate links +- ✅ Not modify existing links +- ✅ Only add new links where needed + +You can safely re-run it: + +```bash +python3 tools/glossary_linker.py website/docs +``` + +### Version Control + +The tool itself should be version controlled: +- Keep `tools/glossary_linker.py` in the repository +- Document any updates in commit messages +- Tag releases if making significant changes + +## Best Practices + +### Do's ✅ + +- Always run in `--dry-run` mode first +- Review changes before committing +- Test locally with `npm start` +- Test production build +- Update term list when adding new glossary entries +- Document any issues or improvements + +### Don'ts ❌ + +- Don't skip the dry-run step +- Don't commit without testing +- Don't manually add glossary links (use the tool) +- Don't modify the tool without testing +- Don't run on uncommitted changes without backup + +## Command Reference + +```bash +# Dry run (preview changes) +python3 tools/glossary_linker.py website/docs --dry-run + +# Apply changes +python3 tools/glossary_linker.py website/docs + +# Save statistics +python3 tools/glossary_linker.py website/docs --output stats.json + +# Help +python3 tools/glossary_linker.py --help +``` + +## Getting Help + +If you encounter issues: + +1. Check this guide's troubleshooting section +2. Review the tool's inline documentation +3. Check recent commits for similar issues +4. Open an issue in the repository with: + - What you tried to do + - What happened + - Error messages or unexpected output + - Your Python version + +## Contributing + +### Reporting Issues + +If you find a problem: + +1. Document the issue with examples +2. Include the command you ran +3. Provide sample markdown that shows the problem +4. Open an issue with this information + +### Suggesting Improvements + +Improvements welcome: +- Better term detection +- Additional glossary terms +- Performance optimizations +- Better error messages + +Submit improvements via pull request. + +## License + +This tool is part of the Robot Framework RFCP Syllabus project and follows the same license. + +## Credits + +Maintained by the Robot Framework Foundation and contributors. + +--- + +**Last Updated:** February 2026 + +**Tool Version:** 3.0 (Final) + +**Compatible With:** Robot Framework RFCP Syllabus v2024+ diff --git a/tools/add_glossary_links.sh b/tools/add_glossary_links.sh new file mode 100644 index 0000000..55cd46e --- /dev/null +++ b/tools/add_glossary_links.sh @@ -0,0 +1,201 @@ +#!/bin/bash +# +# RFCP Syllabus - Add Glossary Links +# One-command automation for the robotframework-RFCP-syllabus repository +# + +set -e + +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +RED='\033[0;31m' +NC='\033[0m' + +echo -e "${BLUE}╔════════════════════════════════════════════════════════════╗${NC}" +echo -e "${BLUE}║ Robot Framework RFCP Syllabus - Glossary Link Automation ║${NC}" +echo -e "${BLUE}╚════════════════════════════════════════════════════════════╝${NC}" +echo "" + +# Check if we're in the repository +if [ ! -d "website/docs" ]; then + echo -e "${RED}Error: website/docs directory not found${NC}" + echo "Please run this script from the robotframework-RFCP-syllabus repository root" + echo "" + echo "Expected structure:" + echo " robotframework-RFCP-syllabus/" + echo " └── website/" + echo " └── docs/" + exit 1 +fi + +# Check if glossary_linker.py exists +if [ ! -f "glossary_linker.py" ]; then + echo -e "${RED}Error: glossary_linker.py not found${NC}" + echo "Please ensure glossary_linker.py is in the repository root" + exit 1 +fi + +# Check for Python +if ! command -v python3 &> /dev/null; then + echo -e "${RED}Error: Python 3 is not installed${NC}" + exit 1 +fi + +echo -e "${GREEN}✓${NC} Repository structure verified" +echo -e "${GREEN}✓${NC} Python 3 found: $(python3 --version)" +echo "" + +# Interactive menu +echo "What would you like to do?" +echo "" +echo " 1) Test mode - Preview changes without modifying files (RECOMMENDED FIRST)" +echo " 2) Apply changes - Add glossary links to all documentation" +echo " 3) Process Chapter 2 only - Test on the chapter with most terms" +echo " 4) Process specific chapter - Choose which chapter to process" +echo " 5) Show statistics from last run" +echo " 6) Exit" +echo "" +read -p "Enter your choice (1-6): " choice + +case $choice in + 1) + echo "" + echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}" + echo -e "${BLUE} TEST MODE - No files will be modified${NC}" + echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}" + echo "" + python3 glossary_linker.py website/docs --dry-run + echo "" + echo -e "${GREEN}✓${NC} Test completed" + echo "" + echo "Review the output above to see what would be changed." + echo "If everything looks good, run this script again and choose option 2." + ;; + + 2) + echo "" + echo -e "${YELLOW}WARNING: This will modify files in website/docs/${NC}" + echo "" + read -p "Have you run test mode first? (y/N): " test_done + if [[ ! $test_done =~ ^[Yy]$ ]]; then + echo -e "${RED}Please run test mode first (option 1)${NC}" + exit 1 + fi + + echo "" + read -p "Are you sure you want to continue? (y/N): " confirm + if [[ ! $confirm =~ ^[Yy]$ ]]; then + echo "Cancelled" + exit 0 + fi + + # Create backup + backup_dir="website_docs_backup_$(date +%Y%m%d_%H%M%S)" + echo "" + echo "Creating backup: $backup_dir" + cp -r website/docs "$backup_dir" + + echo "" + echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}" + echo -e "${BLUE} APPLYING CHANGES${NC}" + echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}" + echo "" + + python3 glossary_linker.py website/docs --output rfcp_glossary_stats.json + + echo "" + echo -e "${GREEN}✓${NC} Changes applied successfully!" + echo -e "${GREEN}✓${NC} Backup created: $backup_dir" + echo -e "${GREEN}✓${NC} Statistics saved: rfcp_glossary_stats.json" + echo "" + echo "Next steps:" + echo " 1. Review changes: git diff website/docs/" + echo " 2. Test locally: cd website && npm start" + echo " 3. Commit: git add website/docs/ && git commit -m 'Add glossary links'" + ;; + + 3) + echo "" + echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}" + echo -e "${BLUE} PROCESSING CHAPTER 2${NC}" + echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}" + echo "" + echo "Chapter 2 contains the most glossary terms (Keyword Interface, Arguments, etc.)" + echo "" + + echo "Step 1: Test mode" + echo "─────────────────" + python3 glossary_linker.py website/docs/chapter-02 --dry-run + + echo "" + read -p "Apply changes to Chapter 2? (y/N): " apply + if [[ $apply =~ ^[Yy]$ ]]; then + echo "" + echo "Step 2: Applying changes" + echo "────────────────────────" + python3 glossary_linker.py website/docs/chapter-02 + echo "" + echo -e "${GREEN}✓${NC} Chapter 2 updated" + echo "Review: git diff website/docs/chapter-02/" + else + echo "No changes made" + fi + ;; + + 4) + echo "" + echo "Available chapters:" + ls -d website/docs/chapter-* 2>/dev/null | sed 's/.*chapter-/ chapter-/' || echo " (no chapters found)" + echo "" + read -p "Enter chapter number (e.g., 02): " chapter_num + + chapter_path="website/docs/chapter-$chapter_num" + if [ ! -d "$chapter_path" ]; then + echo -e "${RED}Error: Chapter not found: $chapter_path${NC}" + exit 1 + fi + + echo "" + echo -e "${BLUE}Processing Chapter $chapter_num${NC}" + echo "" + + echo "Step 1: Test mode" + python3 glossary_linker.py "$chapter_path" --dry-run + + echo "" + read -p "Apply changes? (y/N): " apply + if [[ $apply =~ ^[Yy]$ ]]; then + python3 glossary_linker.py "$chapter_path" + echo "" + echo -e "${GREEN}✓${NC} Chapter $chapter_num updated" + fi + ;; + + 5) + if [ -f "rfcp_glossary_stats.json" ]; then + echo "" + echo -e "${BLUE}Statistics from last run:${NC}" + echo "" + python3 -c "import json; data=json.load(open('rfcp_glossary_stats.json')); print(f\"Total files: {data['total_files']}\"); print(f\"Modified: {data['modified_files']}\"); print(f\"Terms linked: {data['total_terms_linked']}\")" + echo "" + echo "Full details in: rfcp_glossary_stats.json" + else + echo "" + echo -e "${YELLOW}No statistics file found${NC}" + echo "Run option 2 to generate statistics" + fi + ;; + + 6) + echo "Goodbye!" + exit 0 + ;; + + *) + echo -e "${RED}Invalid choice${NC}" + exit 1 + ;; +esac + +echo "" diff --git a/tools/extract_glossary_terms.py b/tools/extract_glossary_terms.py new file mode 100644 index 0000000..9894eab --- /dev/null +++ b/tools/extract_glossary_terms.py @@ -0,0 +1,416 @@ +#!/usr/bin/env python3 +""" +Glossary Term Extractor for Robot Framework RFCP Syllabus + +This script extracts glossary terms from the interactive glossary page +and outputs them in a format that can be used by the glossary linker. +""" + +import json +import re +from typing import List, Dict +from pathlib import Path + + +def extract_from_markdown(glossary_file_path: str) -> List[Dict]: + """ + Extract glossary terms from a markdown glossary file. + + This assumes the glossary is structured with headings for each term. + Adjust the parsing logic based on your actual glossary format. + + Args: + glossary_file_path: Path to the glossary markdown file + + Returns: + List of dictionaries containing term information + """ + terms = [] + + with open(glossary_file_path, 'r', encoding='utf-8') as f: + content = f.read() + + # Example parsing logic - adjust based on your glossary structure + # This is a simplified example assuming each term is a heading + + # Pattern to match glossary entries + # Adjust this regex based on your actual glossary format + pattern = r'###\s+(.+?)\n\n(.+?)(?=\n###|\Z)' + + matches = re.finditer(pattern, content, re.DOTALL) + + for match in matches: + term = match.group(1).strip() + definition = match.group(2).strip() + + # Extract abbreviation if present (example: "Term (ABBR)") + abbr_match = re.search(r'\(([A-Z]{2,})\)', term) + abbreviation = abbr_match.group(1) if abbr_match else '' + + # Clean the term name + term_clean = re.sub(r'\s*\([A-Z]{2,}\)', '', term).strip() + + # Extract aliases from "See also: ..." or "Also known as: ..." + aliases = [] + alias_match = re.search(r'(?:See also|Also known as|Alias(?:es)?)[:\s]+(.+?)(?:\n|$)', definition) + if alias_match: + alias_text = alias_match.group(1) + aliases = [a.strip() for a in re.split(r',|;|\band\b', alias_text)] + + terms.append({ + 'term': term_clean, + 'definition': definition, + 'abbreviation': abbreviation, + 'aliases': aliases + }) + + return terms + + +def extract_from_html_table(html_content: str) -> List[Dict]: + """ + Extract glossary terms from HTML table format. + + This is useful if you're scraping from a rendered HTML page. + + Args: + html_content: HTML content containing the glossary table + + Returns: + List of dictionaries containing term information + """ + from html.parser import HTMLParser + + class GlossaryTableParser(HTMLParser): + def __init__(self): + super().__init__() + self.terms = [] + self.current_term = None + self.current_definition = None + self.in_term_cell = False + self.in_def_cell = False + self.cell_data = [] + + def handle_starttag(self, tag, attrs): + if tag == 'td': + # Determine which column we're in + self.cell_data = [] + + def handle_endtag(self, tag): + if tag == 'td': + if self.current_term is None: + # This is the term cell + self.current_term = ''.join(self.cell_data).strip() + else: + # This is the definition cell + self.current_definition = ''.join(self.cell_data).strip() + + # Process the term + if self.current_term and self.current_definition: + # Check if it's a "See ..." reference + see_match = re.match(r'See\s+(.+)', self.current_definition) + + if see_match: + # This is an alias + # We'll handle this in post-processing + pass + else: + # Extract abbreviation from definition + abbr = '' + abbr_match = re.search(r'\b([A-Z]{2,})\b', self.current_definition) + if abbr_match: + abbr = abbr_match.group(1) + + self.terms.append({ + 'term': self.current_term, + 'definition': self.current_definition, + 'abbreviation': abbr, + 'aliases': [] + }) + + # Reset for next row + self.current_term = None + self.current_definition = None + + def handle_data(self, data): + self.cell_data.append(data) + + parser = GlossaryTableParser() + parser.feed(html_content) + return parser.terms + + +def extract_from_structured_data(data_file: str) -> List[Dict]: + """ + Extract glossary terms from a structured data file (JSON, YAML, etc.). + + Args: + data_file: Path to the data file + + Returns: + List of dictionaries containing term information + """ + with open(data_file, 'r', encoding='utf-8') as f: + if data_file.endswith('.json'): + data = json.load(f) + elif data_file.endswith(('.yml', '.yaml')): + try: + import yaml + data = yaml.safe_load(f) + except ImportError: + raise ImportError("PyYAML is required to parse YAML files. Install it with: pip install pyyaml") + else: + raise ValueError(f"Unsupported file format: {data_file}") + + # Normalize the data structure + if isinstance(data, list): + terms = data + elif isinstance(data, dict) and 'terms' in data: + terms = data['terms'] + else: + terms = [data] + + # Ensure all terms have required fields + for term in terms: + term.setdefault('abbreviation', '') + term.setdefault('aliases', []) + + return terms + + +def manual_term_list() -> List[Dict]: + """ + Returns a manually curated list of glossary terms. + + This is the most reliable method but requires manual maintenance. + Update this list when you add new terms to your glossary. + """ + return [ + # Core Concepts + { + 'term': 'Keyword', + 'definition': 'Named reusable action or sequence of actions in Robot Framework.', + 'abbreviation': '', + 'aliases': [] + }, + { + 'term': 'Suite', + 'definition': 'Collection of tests or tasks defined in a .robot file or directory.', + 'abbreviation': '', + 'aliases': ['Test Suite', 'Task Suite'] + }, + { + 'term': 'Test Case', + 'definition': 'Executable specification that verifies system behavior.', + 'abbreviation': '', + 'aliases': ['Test'] + }, + { + 'term': 'Task', + 'definition': 'Executable entity similar to a test case but used for automation.', + 'abbreviation': '', + 'aliases': [] + }, + + # Arguments + { + 'term': 'Argument', + 'definition': 'Value supplied to a keyword call.', + 'abbreviation': '', + 'aliases': [] + }, + { + 'term': 'Mandatory Argument', + 'definition': 'Argument without a default value that must be provided.', + 'abbreviation': '', + 'aliases': [] + }, + { + 'term': 'Optional Argument', + 'definition': 'Argument that has a default value and may be omitted.', + 'abbreviation': '', + 'aliases': [] + }, + { + 'term': 'Positional Argument', + 'definition': 'Argument provided by position in the argument list.', + 'abbreviation': '', + 'aliases': [] + }, + { + 'term': 'Named Argument', + 'definition': 'Argument provided using an explicit name=value pair.', + 'abbreviation': '', + 'aliases': [] + }, + { + 'term': 'Embedded Argument', + 'definition': 'Argument defined directly in a keyword name using ${} syntax.', + 'abbreviation': '', + 'aliases': [] + }, + { + 'term': 'Positional or Named Argument', + 'definition': 'Argument that can be set either by position or by name.', + 'abbreviation': '', + 'aliases': [] + }, + { + 'term': 'Variable Number of Positional Arguments', + 'definition': 'Optional argument marked with * that collects remaining positional values.', + 'abbreviation': '', + 'aliases': ['*varargs', '*args'] + }, + { + 'term': 'Named-Only Argument', + 'definition': 'Argument that must be provided by name (never positionally).', + 'abbreviation': '', + 'aliases': [] + }, + { + 'term': 'Free Named Argument', + 'definition': 'Catch-all argument marked with ** that gathers undefined named values.', + 'abbreviation': '', + 'aliases': ['kwargs', '**kwargs'] + }, + + # Add more terms as needed... + ] + + +def save_terms(terms: List[Dict], output_file: str, format: str = 'json'): + """ + Save extracted terms to a file. + + Args: + terms: List of term dictionaries + output_file: Path to output file + format: Output format ('json', 'python', or 'yaml') + """ + output_path = Path(output_file) + + if format == 'json': + with open(output_path, 'w', encoding='utf-8') as f: + json.dump(terms, f, indent=2, ensure_ascii=False) + + elif format == 'python': + # Generate Python code + with open(output_path, 'w', encoding='utf-8') as f: + f.write('# Glossary terms extracted from Robot Framework RFCP Syllabus\n') + f.write('# Auto-generated file - do not edit manually\n\n') + f.write('GLOSSARY_TERMS = [\n') + for term in terms: + f.write(' {\n') + f.write(f" 'term': {repr(term['term'])},\n") + f.write(f" 'definition': {repr(term['definition'])},\n") + f.write(f" 'abbreviation': {repr(term.get('abbreviation', ''))},\n") + f.write(f" 'aliases': {repr(term.get('aliases', []))},\n") + f.write(' },\n') + f.write(']\n') + + elif format == 'yaml': + try: + import yaml + with open(output_path, 'w', encoding='utf-8') as f: + yaml.dump(terms, f, allow_unicode=True, default_flow_style=False) + except ImportError: + raise ImportError("PyYAML is required for YAML output. Install it with: pip install pyyaml") + + else: + raise ValueError(f"Unsupported format: {format}") + + print(f"Terms saved to: {output_path}") + + +def merge_aliases(terms: List[Dict]) -> List[Dict]: + """ + Post-process terms to merge "See ..." references into aliases. + + Args: + terms: List of term dictionaries + + Returns: + Processed list with aliases merged + """ + # Build a map of term names to their entries + term_map = {t['term']: t for t in terms} + + # Find and process "See ..." references + see_references = [] + for i, term in enumerate(terms): + see_match = re.match(r'See\s+(.+)', term['definition']) + if see_match: + target_term = see_match.group(1).strip() + if target_term in term_map: + # Add this term as an alias to the target + if term['term'] not in term_map[target_term]['aliases']: + term_map[target_term]['aliases'].append(term['term']) + see_references.append(i) + + # Remove "See ..." entries + for i in reversed(see_references): + terms.pop(i) + + return terms + + +def main(): + """Main function.""" + import argparse + + parser = argparse.ArgumentParser( + description='Extract glossary terms from Robot Framework RFCP Syllabus' + ) + parser.add_argument( + '--input', + help='Input file (markdown, HTML, JSON, or YAML)' + ) + parser.add_argument( + '--input-type', + choices=['markdown', 'html', 'json', 'yaml', 'manual'], + default='manual', + help='Type of input file' + ) + parser.add_argument( + '--output', + default='glossary_terms.json', + help='Output file path' + ) + parser.add_argument( + '--format', + choices=['json', 'python', 'yaml'], + default='json', + help='Output format' + ) + + args = parser.parse_args() + + # Extract terms based on input type + if args.input_type == 'manual': + terms = manual_term_list() + elif args.input_type == 'markdown': + terms = extract_from_markdown(args.input) + elif args.input_type == 'html': + with open(args.input, 'r', encoding='utf-8') as f: + html_content = f.read() + terms = extract_from_html_table(html_content) + elif args.input_type in ['json', 'yaml']: + terms = extract_from_structured_data(args.input) + + # Post-process terms + terms = merge_aliases(terms) + + # Print summary + print(f"Extracted {len(terms)} glossary terms") + print("\nSample terms:") + for term in terms[:5]: + print(f" - {term['term']}") + if term.get('aliases'): + print(f" Aliases: {', '.join(term['aliases'])}") + + # Save to file + save_terms(terms, args.output, args.format) + + +if __name__ == '__main__': + main() diff --git a/tools/glossary_linker.py b/tools/glossary_linker.py new file mode 100644 index 0000000..693a2fd --- /dev/null +++ b/tools/glossary_linker.py @@ -0,0 +1,485 @@ +#!/usr/bin/env python3 +""" +Glossary Linker for Robot Framework RFCP Syllabus (v5 - LO Block Exclusion) + +This script automatically adds links to glossary terms throughout the documentation. + +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 + +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 = {} + + def load_glossary_terms(self, glossary_data: List[Dict]) -> None: + """Load glossary terms and their aliases from provided data.""" + for entry in glossary_data: + term = entry['term'] + slug = self._create_slug(term) + + # Store the main term + self.glossary_terms[term] = slug + + # Store abbreviations as aliases + if entry.get('abbreviation'): + abbr = entry['abbreviation'] + self.aliases[abbr] = (term, slug) + + # Store additional aliases + if entry.get('aliases'): + for alias in entry['aliases']: + self.aliases[alias] = (term, slug) + + def _create_slug(self, term: str) -> str: + """Create a URL-safe slug from a term.""" + slug = term.lower() + slug = re.sub(r'[^\w\s-]', '', slug) + slug = re.sub(r'[\s_]+', '-', slug) + slug = re.sub(r'-+', '-', slug) + slug = slug.strip('-') + return slug + + def _get_relative_path(self, from_file: Path) -> str: + """Calculate the relative path from a file to the glossary.""" + try: + rel_path = from_file.relative_to(self.docs_path) + depth = len(rel_path.parent.parts) + + if depth > 0: + prefix = '../' * depth + return f'{prefix}glossary' + else: + return './glossary' + except ValueError: + return '/docs/glossary' + + def _escape_for_regex(self, term: str) -> str: + """Escape special regex characters in term.""" + return re.escape(term) + + def _extract_frontmatter(self, content: str) -> Tuple[str, str]: + """ + Extract YAML frontmatter from content. + + Returns: + Tuple of (frontmatter, main_content) + """ + frontmatter = "" + main_content = content + + # Check for YAML frontmatter (--- ... ---) + frontmatter_pattern = r'^---\s*\n(.*?)\n---\s*\n' + match = re.match(frontmatter_pattern, content, re.DOTALL) + + if match: + frontmatter = match.group(0) + main_content = content[match.end():] + + return frontmatter, main_content + + def _create_link_patterns(self, current_file: Path) -> List[Tuple[str, str, str]]: + """Create regex patterns for finding and replacing glossary terms.""" + 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' + + # =================================================================== + # NEW: Handle Test|Task notation + # Committee approved: Test|Task something → links to Test something + # =================================================================== + 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: match "Test|Task Something" as a whole phrase + pattern = rf'(? Dict: + """Process a single markdown file and add glossary links.""" + stats = { + 'file': str(file_path.relative_to(self.docs_path)), + 'terms_linked': 0, + 'changes': [] + } + + try: + with open(file_path, 'r', encoding='utf-8') as f: + content = f.read() + + original_content = content + + # Extract frontmatter + frontmatter, main_content = self._extract_frontmatter(content) + + # Get patterns for this file + patterns = self._create_link_patterns(file_path) + + # Track which terms were already linked + already_linked = set() + + # Split content into sections - CRITICAL: exclude headings + sections = self._split_content_sections(main_content) + 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 + for pattern, replacement, term_type in patterns: + matches = list(re.finditer(pattern, modified_content, re.IGNORECASE)) + if matches: + term_matched = matches[0].group(1) + if term_matched not in already_linked: + modified_content = re.sub(pattern, replacement, modified_content, count=0) + stats['terms_linked'] += len(matches) + stats['changes'].append({ + 'term': term_matched, + 'type': term_type, + 'occurrences': len(matches) + }) + already_linked.add(term_matched) + + processed_sections.append(modified_content) + + # Reconstruct content with frontmatter + new_content = frontmatter + ''.join(processed_sections) + + # 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 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-...) + # Pattern matches: :::K1[LO-1.2.3], :::K2[LO-4.5.6-1], etc. + 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 code block start + if line.strip().startswith('```'): + # Collect entire code block + code_block = [line] + i += 1 + while i < len(lines): + code_block.append(lines[i]) + if lines[i].strip().startswith('```'): + i += 1 + break + i += 1 + sections.append(('code', '\n'.join(code_block) + '\n')) + continue + + # Check for inline code or existing links in the line + if '`' in line or '[' in line: + # Split this line more carefully + processed_line = self._process_line_with_special_content(line) + sections.extend(processed_line) + i += 1 + continue + + # Regular text line + sections.append(('text', line + '\n')) + i += 1 + + return sections + + def _process_line_with_special_content(self, line: str) -> List[Tuple[str, str]]: + """ + Process a line that contains inline code or links. + Split it into code/link parts and text parts. + """ + sections = [] + current_pos = 0 + + # Pattern for inline code `...` and links [...](...) + special_pattern = r'`[^`]+`|\[([^\]]+)\]\([^)]+\)' + + for match in re.finditer(special_pattern, line): + # Add text before special content + if current_pos < match.start(): + text_part = line[current_pos:match.start()] + if text_part: + sections.append(('text', text_part)) + + # Add special content (code or link) + sections.append(('code', match.group())) + current_pos = match.end() + + # Add remaining text + if current_pos < len(line): + remaining = line[current_pos:] + if remaining: + sections.append(('text', remaining)) + + # Add newline at the end + if sections: + last_type, last_content = sections[-1] + sections[-1] = (last_type, last_content + '\n') + else: + sections.append(('text', line + '\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) + + if file_stats.get('terms_linked', 0) > 0 or file_stats.get('error'): + overall_stats['files'].append(file_stats) + + return overall_stats + + +# Comprehensive glossary data for RFCP Syllabus +GLOSSARY_DATA = [ + {'term': 'Keyword', 'definition': 'Named reusable action or sequence of actions in Robot Framework.', 'abbreviation': '', 'aliases': []}, + {'term': 'Suite', 'definition': 'Collection of tests or tasks defined in a .robot file or directory.', 'abbreviation': '', 'aliases': ['Test Suite', 'Task Suite']}, + {'term': 'Test Case', 'definition': 'Executable specification that verifies system behavior.', 'abbreviation': '', 'aliases': []}, + {'term': 'Task', 'definition': 'Executable entity for non-testing automation.', 'abbreviation': '', 'aliases': []}, + {'term': 'User Keyword', 'definition': 'Keyword defined in Robot Framework syntax.', 'abbreviation': '', 'aliases': ['Composite Keyword']}, + {'term': 'Keyword Library', 'definition': 'Collection of library keywords.', 'abbreviation': '', 'aliases': ['Library']}, + {'term': 'Resource File', 'definition': 'File containing user keywords and variables.', 'abbreviation': '', 'aliases': []}, + {'term': 'Variable', 'definition': 'Named reference to a value.', 'abbreviation': '', 'aliases': []}, + {'term': 'Argument', 'definition': 'Value supplied to a keyword call.', 'abbreviation': '', 'aliases': []}, + {'term': 'Mandatory Argument', 'definition': 'Argument without a default value.', 'abbreviation': '', 'aliases': []}, + {'term': 'Optional Argument', 'definition': 'Argument with a default value.', 'abbreviation': '', 'aliases': []}, + {'term': 'Positional Argument', 'definition': 'Argument provided by position.', 'abbreviation': '', 'aliases': []}, + {'term': 'Named Argument', 'definition': 'Argument provided using name=value pair.', 'abbreviation': '', 'aliases': []}, + {'term': 'Embedded Argument', 'definition': 'Argument defined in keyword name.', 'abbreviation': '', 'aliases': []}, + {'term': 'Positional or Named Argument', 'definition': 'Argument that can be set by position or name.', 'abbreviation': '', 'aliases': []}, + {'term': 'Variable Number of Positional Arguments', 'definition': 'Optional argument marked with * that collects remaining values.', 'abbreviation': '', 'aliases': ['*varargs', '*args']}, + {'term': 'Named-Only Argument', 'definition': 'Argument that must be provided by name.', 'abbreviation': '', 'aliases': []}, + {'term': 'Free Named Argument', 'definition': 'Catch-all argument marked with **.', 'abbreviation': '', 'aliases': ['kwargs', '**kwargs']}, + {'term': 'Keyword Interface', 'definition': 'Documented information of a keyword.', 'abbreviation': '', 'aliases': []}, + {'term': 'Argument Interface', 'definition': 'Specification of keyword arguments.', 'abbreviation': '', 'aliases': []}, + {'term': 'Return Type Hint', 'definition': 'Indication of return value type.', 'abbreviation': '', 'aliases': []}, + {'term': 'Suite Setup', 'definition': 'Keyword executed before tests in a suite.', 'abbreviation': '', 'aliases': []}, + {'term': 'Suite Teardown', 'definition': 'Keyword executed after tests in a suite.', 'abbreviation': '', 'aliases': []}, + {'term': 'Test Setup', 'definition': 'Keyword executed before a test.', 'abbreviation': '', 'aliases': ['Task Setup']}, + {'term': 'Test Teardown', 'definition': 'Keyword executed after a test.', 'abbreviation': '', 'aliases': ['Task Teardown']}, + {'term': 'Test Tag', 'definition': 'Label for categorization.', 'abbreviation': '', 'aliases': ['Task Tag']}, + {'term': 'Test Template', 'definition': 'Setting for test template.', 'abbreviation': '', 'aliases': ['Task Template']}, + {'term': 'Test Timeout', 'definition': 'Maximum execution time.', 'abbreviation': '', 'aliases': ['Task Timeout']}, + {'term': 'Keyword-Driven Specification', 'definition': 'Style using keyword call sequences.', 'abbreviation': '', 'aliases': []}, + {'term': 'Behavior-Driven Specification', 'definition': 'Style describing user perspective behavior.', 'abbreviation': '', 'aliases': []}, + {'term': 'Data-Driven Specification', 'definition': 'Style with varying input data.', 'abbreviation': '', 'aliases': []}, + {'term': 'Control Structure', 'definition': 'Statement controlling execution flow.', 'abbreviation': '', 'aliases': []}, + {'term': 'FOR Loop', 'definition': 'Structure to iterate over items.', 'abbreviation': '', 'aliases': []}, + {'term': 'WHILE Loop', 'definition': 'Structure repeating while condition is true.', 'abbreviation': '', 'aliases': []}, + {'term': 'Scalar Variable', 'definition': 'Variable with ${} syntax.', 'abbreviation': '', 'aliases': []}, + {'term': 'List Variable', 'definition': 'Variable with @{} syntax.', 'abbreviation': '', 'aliases': []}, + {'term': 'Variable Scope', 'definition': 'Visibility and lifetime of a variable.', 'abbreviation': '', 'aliases': []}, + {'term': 'Global Variable', 'definition': 'Variable with global scope.', 'abbreviation': '', 'aliases': []}, + {'term': 'Suite Variable', 'definition': 'Variable scoped to a suite.', 'abbreviation': '', 'aliases': []}, + {'term': 'Local Variable', 'definition': 'Variable scoped to execution context.', 'abbreviation': '', 'aliases': []}, + {'term': 'Built-In Variables', 'definition': 'Variables provided by Robot Framework.', 'abbreviation': '', 'aliases': []}, + {'term': 'Command Line Interface', 'definition': 'Interface to run Robot Framework.', 'abbreviation': 'CLI', 'aliases': ['Robot Framework CLI']}, + {'term': 'Generic Test Automation Architecture', 'definition': 'Layered reference architecture.', 'abbreviation': 'gTAA', 'aliases': []}, + {'term': 'Definition Layer', 'definition': 'Layer containing test data.', 'abbreviation': '', 'aliases': []}, + {'term': 'Execution Layer', 'definition': 'Layer with execution engine.', 'abbreviation': '', 'aliases': []}, + {'term': 'Adaptation Layer', 'definition': 'Layer connecting to SUT.', 'abbreviation': '', 'aliases': []}, + {'term': 'Execution Artifacts', 'definition': 'Files produced by execution.', 'abbreviation': '', 'aliases': []}, + {'term': 'Output File', 'definition': 'Machine-readable result file.', 'abbreviation': '', 'aliases': ['output.xml']}, + {'term': 'Log File', 'definition': 'Detailed HTML execution log.', 'abbreviation': '', 'aliases': ['log.html']}, + {'term': 'Report File', 'definition': 'High-level HTML summary.', 'abbreviation': '', 'aliases': ['report.html']}, + {'term': 'Pass Status', 'definition': 'Status indicating success.', 'abbreviation': '', 'aliases': []}, + {'term': 'Fail Status', 'definition': 'Status indicating failure.', 'abbreviation': '', 'aliases': []}, + {'term': 'Skip Status', 'definition': 'Status indicating skip.', 'abbreviation': '', 'aliases': []}, + {'term': 'Robot Framework Foundation', 'definition': 'Non-profit steward of Robot Framework.', 'abbreviation': '', 'aliases': []}, + {'term': 'Robot Framework® Certified Professional', 'definition': 'Foundational certification level.', 'abbreviation': 'RFCP', 'aliases': []}, + {'term': 'Robotic Process Automation', 'definition': 'Automation of business processes.', 'abbreviation': 'RPA', 'aliases': []}, + {'term': 'Behavior-Driven Development', 'definition': 'Development approach with business language.', 'abbreviation': 'BDD', 'aliases': []}, + {'term': 'Standard Library', 'definition': 'Library shipped with Robot Framework.', 'abbreviation': '', 'aliases': []}, +] + + +def main(): + """Main function.""" + import argparse + + parser = argparse.ArgumentParser(description='Add glossary links to RFCP Syllabus (with Test|Task support)') + 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"Excluded files: glossary.md") + print() + + stats = linker.process_all_markdown_files(dry_run=args.dry_run) + + print("=" * 60) + print("SUMMARY") + print("=" * 60) + print(f"Total files: {stats['total_files']}") + print(f"Modified: {stats['modified_files']}") + print(f"Terms linked: {stats['total_terms_linked']}") + print() + + if stats['files']: + print("=" * 60) + print("DETAILS") + print("=" * 60) + for file_stats in stats['files'][:10]: # Show first 10 + print(f"\n{file_stats['file']}") + if file_stats.get('error'): + print(f" ERROR: {file_stats['error']}") + else: + print(f" Terms: {file_stats['terms_linked']}") + for change in file_stats['changes'][:3]: + print(f" - {change['term']}: {change['occurrences']}x") + if change['type'] == 'test-task-notation': + print(f" (Test|Task notation)") + + if args.output: + with open(args.output, 'w') as f: + json.dump(stats, f, indent=2) + print(f"\nStats saved: {args.output}") + + +if __name__ == '__main__': + main() diff --git a/tools/quickstart.sh b/tools/quickstart.sh new file mode 100644 index 0000000..c2f2cda --- /dev/null +++ b/tools/quickstart.sh @@ -0,0 +1,239 @@ +#!/bin/bash +# +# Quick Start Script for RFCP Syllabus Glossary Linker +# +# This script provides an easy way to run the glossary linker with common options +# + +set -e # Exit on error + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Script directory +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +LINKER="$SCRIPT_DIR/glossary_linker.py" + +# Function to print colored messages +print_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +print_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +print_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Function to show usage +show_usage() { + cat << EOF +Usage: $0 [OPTION] [DOCS_PATH] + +Automatically add glossary links to Robot Framework RFCP Syllabus documentation. + +OPTIONS: + test Run in test mode (dry-run) without modifying files + apply Apply changes to documentation files + single Process a single chapter (prompts for chapter number) + stats Show statistics from last run + help Show this help message + +DOCS_PATH: + Path to the documentation directory (default: ./docs) + +EXAMPLES: + $0 test # Test mode on ./docs + $0 test ../path/to/docs # Test mode on custom path + $0 apply # Apply changes to ./docs + $0 single # Process single chapter + +For more information, see README_GLOSSARY_LINKER.md +EOF +} + +# Function to check prerequisites +check_prerequisites() { + # Check if Python is available + if ! command -v python3 &> /dev/null; then + print_error "Python 3 is not installed or not in PATH" + exit 1 + fi + + # Check if glossary_linker.py exists + if [ ! -f "$LINKER" ]; then + print_error "glossary_linker.py not found in $SCRIPT_DIR" + exit 1 + fi + + print_success "Prerequisites check passed" +} + +# Function to run test mode +run_test() { + local docs_path="$1" + + print_info "Running in TEST MODE (no files will be modified)" + print_info "Processing: $docs_path" + echo "" + + python3 "$LINKER" "$docs_path" --dry-run + + echo "" + print_success "Test completed successfully" + print_info "Review the output above to see what would be changed" + print_info "If everything looks good, run: $0 apply $docs_path" +} + +# Function to apply changes +run_apply() { + local docs_path="$1" + + print_warning "This will modify files in: $docs_path" + read -p "Are you sure you want to continue? (y/N) " -n 1 -r + echo "" + + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + print_info "Cancelled by user" + exit 0 + fi + + print_info "Applying changes..." + echo "" + + # Create backup + local backup_dir="${docs_path}_backup_$(date +%Y%m%d_%H%M%S)" + print_info "Creating backup: $backup_dir" + cp -r "$docs_path" "$backup_dir" + + # Run the linker + python3 "$LINKER" "$docs_path" --output glossary_stats.json + + echo "" + print_success "Changes applied successfully" + print_info "Backup created at: $backup_dir" + print_info "Statistics saved to: glossary_stats.json" + echo "" + print_info "Next steps:" + echo " 1. Review the changes: git diff $docs_path" + echo " 2. Test the documentation build" + echo " 3. Commit the changes: git add $docs_path && git commit -m 'Add glossary links'" +} + +# Function to process single chapter +run_single() { + local docs_path="$1" + + echo "" + echo "Available chapters in $docs_path:" + ls -d "$docs_path"/chapter-* 2>/dev/null | sed 's/.*chapter-/ chapter-/' || echo " (no chapters found)" + echo "" + + read -p "Enter chapter number (e.g., 02): " chapter_num + + local chapter_path="$docs_path/chapter-$chapter_num" + + if [ ! -d "$chapter_path" ]; then + print_error "Chapter directory not found: $chapter_path" + exit 1 + fi + + print_info "Processing chapter $chapter_num" + echo "" + + # Run in test mode first + print_info "Step 1: Test mode" + python3 "$LINKER" "$chapter_path" --dry-run + + echo "" + read -p "Apply changes to this chapter? (y/N) " -n 1 -r + echo "" + + if [[ $REPLY =~ ^[Yy]$ ]]; then + python3 "$LINKER" "$chapter_path" + print_success "Changes applied to chapter $chapter_num" + else + print_info "No changes made" + fi +} + +# Function to show statistics +show_stats() { + if [ -f "glossary_stats.json" ]; then + print_info "Statistics from last run:" + echo "" + python3 -m json.tool glossary_stats.json + else + print_warning "No statistics file found (glossary_stats.json)" + print_info "Run with 'apply' option to generate statistics" + fi +} + +# Main script + +# Check if no arguments provided +if [ $# -eq 0 ]; then + show_usage + exit 0 +fi + +# Parse command +COMMAND="$1" +DOCS_PATH="${2:-./docs}" + +# Check prerequisites +check_prerequisites + +# Execute command +case "$COMMAND" in + test) + if [ ! -d "$DOCS_PATH" ]; then + print_error "Documentation directory not found: $DOCS_PATH" + exit 1 + fi + run_test "$DOCS_PATH" + ;; + + apply) + if [ ! -d "$DOCS_PATH" ]; then + print_error "Documentation directory not found: $DOCS_PATH" + exit 1 + fi + run_apply "$DOCS_PATH" + ;; + + single) + if [ ! -d "$DOCS_PATH" ]; then + print_error "Documentation directory not found: $DOCS_PATH" + exit 1 + fi + run_single "$DOCS_PATH" + ;; + + stats) + show_stats + ;; + + help|--help|-h) + show_usage + ;; + + *) + print_error "Unknown command: $COMMAND" + echo "" + show_usage + exit 1 + ;; +esac + +exit 0 diff --git a/website/docs/chapter-01/00_overview.md b/website/docs/chapter-01/00_overview.md index f525844..f87d3df 100644 --- a/website/docs/chapter-01/00_overview.md +++ b/website/docs/chapter-01/00_overview.md @@ -1,3 +1,3 @@ # 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](../glossary#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](../glossary#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 68f8de5..c4be23d 100644 --- a/website/docs/chapter-01/01_purpose.md +++ b/website/docs/chapter-01/01_purpose.md @@ -52,9 +52,9 @@ Beyond traditional test levels, **Synthetic Monitoring**, also referred to as ** ## 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](../glossary#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, with its keyword-driven approach, vast ecosystem of libraries, simplicity, and scalability, is widely adopted for [RPA](../glossary#robotic-process-automation) 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 +63,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 4d93df2..fd0746b 100644 --- a/website/docs/chapter-01/02_architecture.md +++ b/website/docs/chapter-01/02_architecture.md @@ -1,6 +1,6 @@ # 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). +Robot Framework is an open-source automation framework that allows you to build automation scripts for testing and [RPA](../glossary#robotic-process-automation) (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. @@ -65,7 +65,7 @@ It includes: However, Robot Framework **does not** include: -- Keyword libraries to control systems under test/RPA. +- [Keyword](../glossary#keyword) libraries to control systems under test/RPA. Such as: - Web front-end automation libraries. @@ -102,3 +102,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 7ddc924..879387d 100644 --- a/website/docs/chapter-01/03_syntax.md +++ b/website/docs/chapter-01/03_syntax.md @@ -69,7 +69,7 @@ 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](../glossary#robotic-process-automation) 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. @@ -104,7 +104,7 @@ 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](../glossary#behavior-driven-development) (BDD) and [Keyword](../glossary#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. @@ -147,8 +147,8 @@ 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](../glossary#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](../glossary#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. @@ -157,3 +157,4 @@ The concepts of organizing are fundamental to working with Robot Framework and c + diff --git a/website/docs/chapter-01/04_styles.md b/website/docs/chapter-01/04_styles.md index 5da19d4..3952991 100644 --- a/website/docs/chapter-01/04_styles.md +++ b/website/docs/chapter-01/04_styles.md @@ -12,10 +12,10 @@ 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. +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](../glossary#robotic-process-automation). 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*. +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](../glossary#keyword)-Driven style*. Further system level test cases, that are not covering acceptance criteria could be written in a *Keyword-Driven style*. The approach of both styles is different in that way, @@ -94,7 +94,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](../glossary#behavior-driven-development) 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. @@ -173,6 +173,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](../glossary#data-driven-specification). + diff --git a/website/docs/chapter-01/05_organization.md b/website/docs/chapter-01/05_organization.md index 7fd7bd9..1c3b646 100644 --- a/website/docs/chapter-01/05_organization.md +++ b/website/docs/chapter-01/05_organization.md @@ -46,7 +46,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](../glossary#robotic-process-automation) 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 +75,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 9c43a64..3ff3ab8 100644 --- a/website/docs/chapter-02/00_overview.md +++ b/website/docs/chapter-02/00_overview.md @@ -9,4 +9,4 @@ 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 +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 b8d52c9..2b27657 100644 --- a/website/docs/chapter-02/01_suitefile.md +++ b/website/docs/chapter-02/01_suitefile.md @@ -19,7 +19,7 @@ If the path to a single file is given as **Root Suite** directly to Robot Framew 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**. +All directories that either directly or indirectly contain a [Suite](../glossary#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. @@ -75,7 +75,7 @@ Robot Framework parses files with the extension `.robot` and searches for test c 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. +A Suite File **either** contains `*** Test Cases ***` (in Test Suites) **or** `*** Tasks ***` (in [Task](../glossary#task) Suites), but it CANNOT contain both types simultaneously. @@ -164,7 +164,7 @@ 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. 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](../glossary#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 +194,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. - + ### 2.1.2.4 Introduction to `*** Keywords ***` Section @@ -233,3 +233,4 @@ All content in this section is ignored by Robot Framework and is not executed or + diff --git a/website/docs/chapter-02/02_suitefile_syntax.md b/website/docs/chapter-02/02_suitefile_syntax.md index dd49fa1..56e341e 100644 --- a/website/docs/chapter-02/02_suitefile_syntax.md +++ b/website/docs/chapter-02/02_suitefile_syntax.md @@ -17,7 +17,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](../glossary#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). @@ -301,3 +301,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 9898eb9..e2452f5 100644 --- a/website/docs/chapter-02/03_executing.md +++ b/website/docs/chapter-02/03_executing.md @@ -112,7 +112,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](../glossary#suite), [Test Case](../glossary#test-case), [Task](../glossary#task) and [Keyword](../glossary#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. @@ -122,7 +122,7 @@ Additional Keyword Status: `SKIP` is explained in more detail in later chapters. -**Atomic elements** like Library Keywords or Robot Framework language statements do define their own status. +**Atomic elements** like [Library](../glossary#keyword-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. @@ -144,7 +144,7 @@ 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](../glossary#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. @@ -199,3 +199,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 aed738e..1094467 100644 --- a/website/docs/chapter-02/04_keyword_imports.md +++ b/website/docs/chapter-02/04_keyword_imports.md @@ -123,7 +123,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](../glossary#command-line-interface)-[Argument](../glossary#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. @@ -137,3 +137,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 0c7e930..02ae287 100644 --- a/website/docs/chapter-02/05_keyword_interface.md +++ b/website/docs/chapter-02/05_keyword_interface.md @@ -11,12 +11,12 @@ 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](../glossary#keyword-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. 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. +Basically all standard and external 3rd party libraries offer these [Keyword](../glossary#keyword) Documentations as online available HTML pages. Robot Framework offers the Keyword Documentation of its Standard Libraries at https://robotframework.org/robotframework . @@ -73,11 +73,11 @@ All of them can be called positionally or by name. This keyword has one :term[Mandatory Arguments]{tooltipMd="An **Argument** that must be set.
See [Mandatory Args](chapter-03/03_user_keyword.md)"} `command` which can be called positionally or by name. The latter two arguments are optional. -The argument `arguments` is a "Variable Number of Positional Arguments" and can only be set by position. +The argument `arguments` is a "[Variable Number of Positional Arguments](../glossary#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. -The argument `configuration` is a "Free Named Argument" and can only be set by names. +The argument `configuration` is a "[Free Named Argument](../glossary#free-named-argument)" and can only be set by names. See [2.5.2.7 Free Named Arguments](chapter-02/05_keyword_interface.md#2527-free-named-arguments) for more information about this kind of argument. @@ -92,11 +92,11 @@ See [2.5.2.7 Free Named Arguments](chapter-02/05_keyword_interface.md#2527-free- This keyword has 2 "Mandatory Arguments" that can be called positionally or by name. The last two arguments are optional. -The argument `groups` is a "Variable Number of Positional Arguments" and can only be set by position. +The argument `groups` is a "[Variable](../glossary#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. -The argument `flags` is a "Named-Only Argument" and can only be set by name. +The argument `flags` is a "[Named-Only Argument](../glossary#named-only-argument)" and can only be set by name. See [2.5.2.6 Named-Only Arguments](chapter-02/05_keyword_interface.md#2526-named-only-arguments) for more information about this kind of argument. @@ -211,7 +211,7 @@ 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). +Keywords can include arguments embedded directly into their names, a feature primarily used for [Behavior-Driven Development](../glossary#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}`). @@ -223,7 +223,7 @@ Example keyword names are: - `the page title should be ${exp_title}` - `the url should be ${exp_url}` -Example Test Case: +Example [Test Case](../glossary#test-case): ```robotframework *** Test Cases *** Foundation Page should be Accessible @@ -235,7 +235,7 @@ 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 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. +A mix of embedded arguments and "normal" arguments is possible to fully support [BDD](../glossary#behavior-driven-development). 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. @@ -466,3 +466,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 7ebb4a9..f88492f 100644 --- a/website/docs/chapter-02/06_writing_test.md +++ b/website/docs/chapter-02/06_writing_test.md @@ -12,7 +12,7 @@ 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. +When using keywords in a test|task or [User Keyword](../glossary#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. @@ -21,7 +21,7 @@ The following example shows different ways to call imported keywords in a test c 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](../glossary#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". @@ -100,7 +100,7 @@ Click on x and y Click On Coordinates x=82 y=70 ``` -Calling keywords that have a "Variable Number of Positional Arguments" does require to set all preceding arguments by their position if the "Variable Number of Positional Arguments" shall be set. +Calling keywords that have a "[Variable Number of Positional Arguments](../glossary#variable-number-of-positional-arguments)" does require to set all preceding arguments by their position if the "[Variable Number of Positional Arguments](../glossary#variable-number-of-positional-arguments)" shall be set. Example: ```robotframework @@ -128,7 +128,7 @@ 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. +[Keyword](../glossary#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. @@ -161,7 +161,7 @@ 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](../glossary#behavior-driven-development) (BDD) using Robot Frameworks [Behavior-Driven Specification](../glossary#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). @@ -169,4 +169,4 @@ When calling keywords with embedded arguments, all characters that are at the po 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 ba07811..fb321c6 100644 --- a/website/docs/chapter-03/00_overview.md +++ b/website/docs/chapter-03/00_overview.md @@ -1,3 +1,4 @@ # 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](../glossary#robotic-process-automation) contexts. + diff --git a/website/docs/chapter-03/01_resource_file.md b/website/docs/chapter-03/01_resource_file.md index 5bbc0ce..ef5786a 100644 --- a/website/docs/chapter-03/01_resource_file.md +++ b/website/docs/chapter-03/01_resource_file.md @@ -47,7 +47,7 @@ The allowed sections in recommended order are: 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](../glossary#keyword) tags is not part of this syllabus. Other settings available in suites are not available in resource files. @@ -65,3 +65,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 16e94e5..50b4346 100644 --- a/website/docs/chapter-03/02_variables.md +++ b/website/docs/chapter-03/02_variables.md @@ -60,7 +60,7 @@ Variables in Robot Framework are defined by three attributes: - **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. -Variable names are case-insensitive and as keywords, containing single spaces and underscores are ignored when matching variable names. +[Variable](../glossary#variable) names are case-insensitive and as keywords, containing single spaces and underscores are ignored when matching variable names. Robot Framework supports Unicode and allows the use of special characters and even Emojis in variable names. In case these prefixes followed by a curly brace opening (`${`) should be used as characters in a normal string and not as a variable, @@ -468,3 +468,4 @@ Examples and more details on variable scope, such as `TEST` and `GLOBAL` scope c + diff --git a/website/docs/chapter-03/03_user_keyword.md b/website/docs/chapter-03/03_user_keyword.md index 35e1c74..24cf826 100644 --- a/website/docs/chapter-03/03_user_keyword.md +++ b/website/docs/chapter-03/03_user_keyword.md @@ -56,18 +56,18 @@ The names of User Keywords should be descriptive and clear, reflecting the purpo 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. -Keyword names are case-insensitive and can include single spaces. +[Keyword](../glossary#keyword) names are case-insensitive and can include single spaces. 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. - If then a full match is found, that keyword is used. -- If no full match is found, 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 full match is found, the prefixes `Given`, `When`, `Then`, `And`, and `But` (case-insensitive), which are used in [Behavior-Driven Specification](../glossary#behavior-driven-specification) style, are removed from the called keyword name to find a match. - If still no match is found, Robot Framework tries to match the name with keywords that have embedded arguments. -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. +By default, if not explicitly defined by the library developers, all [Library](../glossary#keyword-library) Keywords are named in **Title Case** with capital letters at the beginning of each word, and spaces between words. -Project may choose a different naming convention for User Keywords, but it is recommended to be consistent across the project for User Keyword names. +Project may choose a different naming convention for User Keywords, but it is recommended to be consistent across the project for [User Keyword](../glossary#user-keyword) names. They are defined without indentation, and the subsequent lines until the next unindented line are considered the body of the keyword. The following topics explain how to structure the body of a keyword. @@ -453,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 42e8d37..127069e 100644 --- a/website/docs/chapter-03/04_datadriven.md +++ b/website/docs/chapter-03/04_datadriven.md @@ -129,3 +129,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 be27581..7042cd5 100644 --- a/website/docs/chapter-03/05_advanced_importing.md +++ b/website/docs/chapter-03/05_advanced_importing.md @@ -104,7 +104,7 @@ 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. +[Library](../glossary#keyword-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. @@ -194,3 +194,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 def9ade..6ee3968 100644 --- a/website/docs/chapter-04/00_overview.md +++ b/website/docs/chapter-04/00_overview.md @@ -4,4 +4,4 @@ As a Robot Framework automation project expands, the increasing number of tests| 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 b7a8f18..5e98468 100644 --- a/website/docs/chapter-04/01_setups.md +++ b/website/docs/chapter-04/01_setups.md @@ -21,7 +21,7 @@ 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. -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](../glossary#suite-setup). Examples of typical use cases for Setups are: - Establishing connections to databases or services. @@ -54,7 +54,7 @@ A **Suite Setup** is executed before any tests|tasks or child suites within the It is used to prepare the environment or perform actions that need to occur before the entire suite runs. Since it is only executed once before all tests|tasks or child suites, it can save time, rather than executing the action for each test|task individually. -**Key characteristics of Suite Setup:** +**Key characteristics of [Suite](../glossary#suite) Setup:** - Suite Setup is a single keyword call with potential argument values. - Executed before any tests|tasks and child suites in the suite. - If the Suite Setup fails, all tests|tasks in the suite and its child suites are marked as failed, and they are not executed. @@ -94,16 +94,16 @@ Understand when Test|Task Setup is executed and used :::: -A **Test|Task Setup** is executed before a single test|task runs. +A **Test|[Task](../glossary#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](../glossary#test-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. To disable the setup for a specific test|task, you can set `[Setup] NONE`, which means that no setup will be executed for that test|task. -**Key characteristics of Test|Task Setup:** +**Key characteristics of Test|[Task Setup](../glossary#test-setup):** - Test|Task Setup is a single keyword call with potential argument values. - Executed before the test|task starts. - If the Test|Task Setup fails, the test|task is marked as failed, and its body, including its main keywords, is not executed. @@ -155,7 +155,7 @@ Recall key characteristics and syntax of Keyword Setup 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:** +**Key characteristics of [Keyword](../glossary#keyword) Setup:** - Keyword Setup is a single keyword call with potential argument values. - Executed before the keyword's body. - If the Keyword Setup fails, the keyword's body is not executed. @@ -178,3 +178,4 @@ Process Data + diff --git a/website/docs/chapter-04/02_teardowns.md b/website/docs/chapter-04/02_teardowns.md index eefb7e7..8fae768 100644 --- a/website/docs/chapter-04/02_teardowns.md +++ b/website/docs/chapter-04/02_teardowns.md @@ -58,12 +58,12 @@ 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](../glossary#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:** +**Key characteristics of [Suite](../glossary#suite) Teardown:** - Suite Teardown is a single keyword call with potential argument values. - Executed after all tests|tasks and child suites have completed. -- Runs even if the Suite Setup fails or any test|task within the suite fails. +- Runs even if the [Suite Setup](../glossary#suite-setup) fails or any test|task within the suite fails. - If the Suite Teardown fails, all tests|tasks in the suite are marked as failed in reports and logs. - All keywords within the Suite Teardown are executed, even if one of them fails, ensuring all cleanup actions are attempted. @@ -98,11 +98,11 @@ Understand when Test|Task Teardown is executed and used :::: -A **Test|Task Teardown** is executed after a single test|task body has been executed. +A **Test|[Task](../glossary#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](../glossary#test-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. +In Robot Framework, you can define a default Test|[Task Teardown](../glossary#test-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. Individual tests|tasks can override the default teardown by specifying their own `[Teardown]` setting within the test|task. @@ -113,7 +113,7 @@ 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](../glossary#test-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. @@ -170,7 +170,7 @@ ensuring that any resources used within the keyword are properly released indepe For better readability, it should be written as the last line of a keyword. -**Key characteristics of Keyword Teardown:** +**Key characteristics of [Keyword](../glossary#keyword) Teardown:** - Keyword Teardown is a single keyword call with potential argument values. - Executed after the keyword body has been executed, regardless of its status. - Runs even if the keyword's setup fails. @@ -194,3 +194,4 @@ Process Data + diff --git a/website/docs/chapter-04/03_init_files.md b/website/docs/chapter-04/03_init_files.md index 2a6d59d..50a7f02 100644 --- a/website/docs/chapter-04/03_init_files.md +++ b/website/docs/chapter-04/03_init_files.md @@ -45,8 +45,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](../glossary#suite-setup) that is executed at the very start of the execution before any other [Suite Setup](../glossary#suite-setup), [Test|[Task](../glossary#task) Setup](../glossary#test-setup), and Test|[Task](../glossary#task) is executed. +The [Suite Teardown](../glossary#suite-teardown) of an initialization file is executed after all sub-suites in the directory and their tests|tasks have been completed. @@ -84,7 +84,7 @@ The following sections are allowed in initialization files: - **`*** 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](../glossary#suite) Setup, [Suite](../glossary#suite) Teardown, [Test Setup](../glossary#test-setup), or [Test Teardown](../glossary#test-teardown). - **`*** Comments ***` Section (optional)**: @@ -125,3 +125,4 @@ Cleanup Environment + diff --git a/website/docs/chapter-04/04_tags.md b/website/docs/chapter-04/04_tags.md index 5115927..23893b1 100644 --- a/website/docs/chapter-04/04_tags.md +++ b/website/docs/chapter-04/04_tags.md @@ -34,7 +34,7 @@ Recall the syntax and different ways to assign tags to tests|tasks Tags can be assigned to tests|tasks in several ways: -1. **At the Suite Level** using the `Test Tags` setting in the `*** Settings ***` section or in an initialization file (`__init__.robot`). +1. **At the [Suite](../glossary#suite) Level** using the `Test Tags` setting in the `*** Settings ***` section or in an initialization file (`__init__.robot`). This assigns tags to all tests|tasks within the suite: ```robotframework @@ -44,7 +44,7 @@ Tags can be assigned to tests|tasks in several ways: This will assign the tags `smoke` and `regression` to all tests|tasks in the suite. -2. **At the Test|Task Level** using the `[Tags]` setting within individual tests|tasks. These tags are added in addition to any suite-level tags: +2. **At the Test|[Task](../glossary#task) Level** using the `[Tags]` setting within individual tests|tasks. These tags are added in addition to any suite-level tags: ```robotframework *** Test Cases *** @@ -70,7 +70,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](../glossary#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 +162,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 b4b54f4..ddd3004 100644 --- a/website/docs/chapter-04/05_skip.md +++ b/website/docs/chapter-04/05_skip.md @@ -22,7 +22,7 @@ In addition to `PASS` and `FAIL`, Robot Framework introduces the `SKIP` status t **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](../glossary#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. @@ -59,7 +59,7 @@ Therefore skip is better for documenting that a specific test|task was not execu 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](../glossary#task) Teardown](../glossary#test-teardown) exists, it will be executed. ## 4.5.3 Automatically Skipping Failed Tests @@ -73,3 +73,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 be5fba1..4013433 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 133198b..1456e50 100644 --- a/website/docs/chapter-05/01_advanced_variables.md +++ b/website/docs/chapter-05/01_advanced_variables.md @@ -6,7 +6,7 @@ Robot Framework also offers multiple ways to create different kinds of values an 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](../glossary#built-in-variables). 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. @@ -154,7 +154,7 @@ Recall how to define suite variables and where they can be accessed - Set during the execution of a suite using the `VAR` syntax with the `scope=SUITE` argument. (dynamic) - **Usage**: Useful for sharing data among tests/tasks within the same suite or configuring suite-specific settings or setting default values for global variables. -Suite scope is not recursive; variables in a higher-level suite, e.g. defined in [4.3 Initialization Files](chapter-04/03_init_files.md), are not available in lower-level suites. Use resource files to share variables across suites. +[Suite](../glossary#suite) scope is not recursive; variables in a higher-level suite, e.g. defined in [4.3 Initialization Files](chapter-04/03_init_files.md), are not available in lower-level suites. Use resource files to share variables across suites. Variables with a suite scope are generally statically defined or imported variables, but they can also be created dynamically during the execution of a suite. In this latter case, they have a higher priority than statically defined variables and can shadow or overwrite them. @@ -182,7 +182,7 @@ Recall how to define test|task variables and where they can be accessed - 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](../glossary#task) variables cannot be created in suite setup or teardown, nor can they be imported. Test|[Task](../glossary#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 +207,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](../glossary#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. @@ -430,7 +430,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: -| Variable | Description | +| [Variable](../glossary#variable) | Description | |--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------| | `${EMPTY}` | An empty string. | | `${SPACE}` | A single space character. | @@ -455,3 +455,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 8d66052..9fdcdad 100644 --- a/website/docs/chapter-05/02_control_structures.md +++ b/website/docs/chapter-05/02_control_structures.md @@ -298,3 +298,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 f2e196f..2039c81 100644 --- a/website/docs/example-exam/Example-exam.mdx +++ b/website/docs/example-exam/Example-exam.mdx @@ -5,3 +5,4 @@ import Quiz from '@site/src/components/Quiz/Quiz'; 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/overview.md b/website/docs/overview.md index 7f4df54..72dada0 100644 --- a/website/docs/overview.md +++ b/website/docs/overview.md @@ -9,7 +9,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](./glossary#robot-framework-certified-professional)" ([RFCP](./glossary#robot-framework-certified-professional)®) 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 @@ -87,7 +87,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](./glossary#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 +144,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.