Nikolaus Rieder — 42 Vienna
March 16, 2026
All material: hackxit.github.io/42vienna-robotframework-workshop
Slides cover points 1–5, then we switch to live coding
Let's get everyone ready while we talk
github.com/HackXIt/42vienna-robotframework-workshopThis installs Python, Node.js, Robot Framework, Browser Library, and Chromium — all automatic.
When your Codespace terminal is ready, run:
uv run robot tests/00_setup_verification/
You should see:
1 test, 1 passed, 0 failed
Problems? Run python scripts/check_environment.py for diagnostics.
| Domain | Library | Technology |
|---|---|---|
| Web (E2E) | Browser Library | Playwright |
| Web (legacy) | SeleniumLibrary | Selenium WebDriver |
| REST API | RequestsLibrary / RESTinstance | HTTP |
| Mobile | AppiumLibrary | Appium |
| Desktop | Various | OS-specific |
| RPA | rpaframework | Multi |
Compare: Cypress = web only. Postman = API only. Appium = mobile only.
Robot Framework = one syntax across all of them.
Not typically used for: unit testing, component testing (use pytest, JUnit instead)
▲ Acceptance / E2E Testing ← Robot Framework ▲ System Integration Testing ← Robot Framework ▲ System Testing ← Robot Framework ▲ Integration Testing ← rarely RF ▲ Unit / Component Testing ← pytest, JUnit
RF operates at higher test levels, automating real user workflows
How Robot Framework is built
.robot files, builds execution modellog.html, report.html, output.xmlAligned with the ISTQB Generic Test Automation Architecture
These come from the ecosystem:
Libraries, editors (RobotCode, RIDE), CI tools (GitHub Actions, Jenkins)
This is by design — RF is the framework, not the toolbox.
Your Test Cases ← you write these ↓ Robot Framework ← parses & executes ↓ Browser Library ← Playwright wrapper (adaptation layer) ↓ Playwright ← browser automation engine ↓ Chromium ← the actual browser
The language of Robot Framework
Convention: use 4 spaces between keyword and arguments for clarity
| Extension | Contains | Purpose |
|---|---|---|
.robot |
Test Cases or Tasks | Executable test suite |
.resource |
Keywords & Variables | Reusable components |
__init__.robot |
Suite settings | Directory-level config |
A directory containing .robot files is also a suite — forming a hierarchy.
*** Settings ***
Documentation What this suite is about
Library Browser
Resource ../resources/common.resource
*** Variables ***
${URL} https://www.saucedemo.com
${USER} standard_user
*** Test Cases ***
My First Test
[Documentation] Verify login works
Log Hello World
*** Keywords ***
My Custom Keyword
[Arguments] ${arg1}
Log Got: ${arg1}
The most important syntax concept:
# This works (4 spaces between keyword and args):
Click id=login-button
# This ALSO works (2 spaces):
Click id=login-button
# This FAILS (only 1 space):
Click id=login-button
# ^^^^^^^^^^^^^^^^
# RF thinks the keyword name is "Click id=login-button"
Rule: 2+ spaces (or tab) = argument separator
Convention: Use 4 spaces for readability
*** Variables ***
${SCALAR} single value # String
${NUMBER} ${42} # Integer
${BOOL} ${True} # Boolean
@{LIST} item1 item2 # List
&{DICT} key1=val1 key2=val2 # Dictionary
*** Test Cases ***
Using Variables
Log ${SCALAR} # single value
Log ${LIST}[0] # item1
Log ${DICT}[key1] # val1
${} = scalar
@{} = list
&{} = dictionary
Written in RF syntax
Combine other keywords into higher-level steps
Live in .robot or .resource files
Login As Standard User
Fill Text id=user-name
... standard_user
Fill Text id=password
... secret_sauce
Click id=login-button
Written in Python (or other)
Interact directly with systems
Installed as packages
# Python behind "Fill Text":
def fill_text(selector, text):
page.locator(selector)
.fill(text)
How tests can be written
"What actions to perform"
*** Test Cases ***
Purchase A Product
Login With Credentials standard_user secret_sauce
Add Product To Cart Sauce Labs Backpack
Open Cart
Proceed To Checkout
Fill Checkout Info John Doe 12345
Complete Purchase
Verify Order Confirmation
Procedural, step-by-step — great for technical audiences
"How the system should behave"
*** Test Cases ***
User Can Purchase A Product
Given the user is logged in as "standard_user"
When the user adds "Sauce Labs Backpack" to the cart
And the user completes checkout with name "John Doe"
Then the order confirmation should be displayed
Given/When/Then/And/But prefixes are stripped by RF at runtime
Maps to user stories — great for stakeholder communication
"Same flow, different data"
*** Test Cases *** USERNAME PASSWORD EXPECTED
Valid Login standard_user secret_sauce Products
Locked User locked_out_user secret_sauce locked out
Wrong Password standard_user wrong_pass do not match
Empty Username ${EMPTY} secret_sauce Username is required
*** Keywords ***
Login And Verify
[Arguments] ${username} ${password} ${expected}
Login With Credentials ${username} ${password}
# ... verify expected outcome
Uses [Template] — each row is a test case with different data
| Keyword-Driven | BDD | Data-Driven | |
|---|---|---|---|
| Focus | Actions | Behavior | Data variations |
| Style | Imperative | Declarative | Template |
| Best for | Technical detail | Business requirements | Combinatorial testing |
| Audience | Engineers | Mixed stakeholders | Engineers |
In practice: keyword-driven is the most common style. Today's workshop uses keyword-driven.
Structuring reusable automation
test_login.robot imports ↓ login_page.resource ← keywords: Login With Credentials, Login Should Fail, ... imports ↓ common.resource ← keywords: Open SauceDemo, Close SauceDemo imports ↓ Browser Library ← keywords: Click, Fill Text, Get Text, Get Url, ...
Each page of the application gets its own resource file.
Tests use descriptive keyword names, not raw CSS selectors.
*** Settings ***
Documentation Login page keywords for SauceDemo
Library Browser
*** Variables ***
${LOGIN_USER_FIELD} id=user-name
${LOGIN_PASS_FIELD} id=password
${LOGIN_BUTTON} id=login-button
${ERROR_CONTAINER} css=.error-message-container
*** Keywords ***
Login With Credentials
[Documentation] Fill username/password and click login
[Arguments] ${username} ${password}
Fill Text ${LOGIN_USER_FIELD} ${username}
Fill Text ${LOGIN_PASS_FIELD} ${password}
Click ${LOGIN_BUTTON}
Selector changes? Update one file, not every test.
tests/
00_setup_verification/ # Smoke test
01_first_test/ # Intro with comments
02_login_tests/ # Login page tests
03_product_tests/ # Product catalog
04_cart_tests/ # Shopping cart
05_checkout_tests/ # Checkout flow
06_e2e_scenarios/ # Full purchase flow
student_exercises/ # YOUR tests go here
resources/
common.resource # Setup/teardown, base URL
login_page.resource # Login keywords
products_page.resource # Products keywords
cart_page.resource # Cart keywords
checkout_page.resource # Checkout keywords
Managing test lifecycle
| Level | Runs | Use Case |
|---|---|---|
Suite Setup |
Once before all tests in suite | Open browser |
Suite Teardown |
Once after all tests | Close browser |
Test Setup |
Before each test | Navigate to start page |
Test Teardown |
After each test | Take screenshot |
*** Settings ***
Suite Setup Open SauceDemo
Suite Teardown Close SauceDemo
Test Setup Go To ${BASE_URL}
*** Test Cases ***
Login With Valid Credentials
[Tags] smoke login positive
Login With Credentials standard_user secret_sauce
Login Should Succeed
Run subsets by tag:
# Only smoke tests
uv run robot --include smoke tests/
# Everything except slow tests
uv run robot --exclude slow tests/
# Combine: smoke AND login
uv run robot --include smokeANDlogin tests/
Stretch, grab coffee, check your Codespace
Make sure uv run robot tests/00_setup_verification/ passes!
The tools we use today
*** Keywords ***
Open SauceDemo
New Browser chromium headless=${HEADLESS}
New Context
New Page ${BASE_URL}
Browser = Chromium/Firefox/WebKit process
Context = isolated session (cookies, storage)
Page = a tab
# By ID (most reliable)
Click id=login-button
# By CSS selector
Click css=.inventory_item_name
Get Text css=.shopping_cart_badge == 1
# By text content
Click text=Sauce Labs Backpack
# Combined
Click css=.btn_primary >> text=Add to cart
Browser Library uses Playwright selectors — powerful, auto-waiting.
| Action | Keyword | Example |
|---|---|---|
| Navigate | Go To | Go To ${URL} |
| Click | Click | Click id=login-button |
| Type text | Fill Text | Fill Text id=user-name admin |
| Read text | Get Text | Get Text css=.title == Products |
| Check URL | Get Url | Get Url *= /inventory |
| Screenshot | Take Screenshot | Take Screenshot |
# Exact match
Get Text css=.title == Products
# Contains
Get Text css=.error *= locked out
# Starts with
Get Url ^= https://www.saucedemo.com
# Greater/less than (for counts, prices, etc.)
Get Element Count css=.inventory_item >= 1
No need for separate Should Be Equal —
assertions are built into getter keywords.
| Username | Behavior |
|---|---|
standard_user | Normal user (primary account) |
locked_out_user | Always locked out |
problem_user | Has UI bugs |
performance_glitch_user | Slow responses |
error_user | Returns errors |
visual_user | Visual differences |
Password for all users: secret_sauce
Login → Products → Cart → Checkout Info → Checkout Overview → Confirmation
This is the complete E2E flow you'll automate in the exercises.
You push code ↓ GitHub Actions triggers ↓ ├ Robocop lint → code quality check (SARIF → Code Scanning) └ Robot Framework → runs ALL tests in headless Chromium ↓ Results posted as PR comment
Status: All tests passed!
29 tests, 29 passed, 0 failed
Status: No issues found.
Every PR gets automated feedback — no manual test running needed.
What we covered maps to the official RFCP syllabus:
| Chapter | Topic | Today |
|---|---|---|
| 1.1 | Purpose & Use Cases | ✓ |
| 1.2 | Architecture (gTAA) | ✓ |
| 1.3 | Basic Syntax & Structure | ✓ |
| 1.4 | Specification Styles | ✓ |
| 2 | Getting Started, Libraries, Keywords | ✓ (hands-on) |
| 3 | Variables, Resource Files, Data-Driven | ✓ (hands-on) |
| 4 | Setup/Teardown, Tags | ✓ |
| 5 | Advanced Constructs (IF/FOR) | brief |
Time to write tests!
Open your Codespace and go to:
hackxit.github.io/.../exercises
cp tests/student_exercises/_template.robot tests/student_exercises/yourname_exercise_1.robot
uv run robot tests/student_exercises/yourname_*.robotresults/log.htmlI'll walk around and help. Ask questions!
Keep working if you're in the flow, or take a breather
Live demo — generating tests with AI
.robot file
AI doesn't replace testers — it accelerates test creation.
You design the strategy. AI generates the boilerplate.
# Stage your files
git add tests/student_exercises/yourname_*.robot
# Commit
git commit -m "Add exercises by yourname"
# Push to your fork
git push origin main
Then on GitHub: Contribute → Open pull request
CI will run automatically and post results on your PR!
Nikolaus Rieder
github.com/HackXIt