Selenium IDE Test Guide
Purpose and Audience
This guide documents how to create and maintain browser automation tests using the Selenium IDE 2.0 JSON format (.side files) for the PCR Analysis system. These are end-to-end UI tests that validate application behavior through browser interaction, typically targeting the pre-production environment.
Audience: Developers and QA Engineers responsible for writing, maintaining, or reviewing browser-based automated tests.
Tests are stored as .side files in the exports/ghostinspector/ directory of the test repository. The format is compatible with both Selenium IDE and Ghost Inspector import/export.
See the Testing Guide for Behat/Cucumber test writing.
File Format
Selenium IDE 2.0 JSON format (.side extension).
Root Structure
{
"id": "uuid",
"version": "2.0",
"name": "Project Name",
"url": "",
"urls": [],
"tests": [
// Array of test objects
]
}
| Field | Type | Description |
|---|---|---|
id | string | UUID for the project |
version | string | Always "2.0" |
name | string | Project/suite name |
url | string | Default base URL (can be empty if using variables) |
urls | array | Additional URLs (usually empty) |
tests | array | Array of test objects |
Test Object Structure
{
"id": "uuid",
"name": "Test Name",
"commands": [
// Array of command objects
]
}
| Field | Type | Description |
|---|---|---|
id | string | UUID for the test |
name | string | Test name |
commands | array | Array of command objects |
Command Object Structure
{
"id": "uuid",
"comment": "Description of command",
"command": "selenium_command",
"target": "selector or value",
"targets": [],
"value": "parameter value"
}
| Field | Type | Description |
|---|---|---|
id | string | UUID for the command |
comment | string | Description/comment for the command |
command | string | Selenium IDE command name |
target | string | Primary target (selector, URL, value) |
targets | array | Alternative targets (usually empty) |
value | string | Secondary value/parameter |
Common Commands Reference
Navigation
{"command": "open", "target": "${URL_root}/login/admin", "value": ""}
{"command": "setWindowSize", "target": "1280x800", "value": ""}
Variables
{"command": "store", "target": "username_value", "value": "username"}
{"command": "store", "target": "password_value", "value": "password"}
Input
{"command": "type", "target": "xpath=//input[@id=\"username-field\"]", "value": "${username}"}
{"command": "sendKeys", "target": "css=input", "value": "${variable}"}
Clicks
{"command": "click", "target": "css=button[type=\"submit\"]", "value": ""}
{"command": "click", "target": "xpath=//button[.//span[text()=\"Apply\"]]", "value": ""}
Waits/Pauses
{"command": "pause", "target": "2000", "value": ""}
Assertions
{"command": "assertElementPresent", "target": "css=#token", "value": ""}
{"command": "assert", "target": "checkReturnValue", "value": "true"}
JavaScript Execution
{"command": "executeScript", "target": "return window.location.href", "value": "mfa_link"}
{"command": "executeScript", "target": "const element = document.querySelector('#token');\nreturn element.textContent;", "value": "totp"}
Conditional Logic
{"command": "if", "target": "!!${checkConditionalValue}", "value": ""}
{"command": "end", "target": "", "value": ""}
Selector Types
CSS Selectors
css=button[type="submit"]
css=#token
css=input[placeholder="The secret key"]
XPath Selectors
xpath=//input[@id="username-field"]
xpath=//button[.//span[text()="Apply"]]
xpath=//div[contains(@class, "filter-name") and normalize-space(text())="Actions"]
xpath=//div[@title="LJ Report"]
Variable Usage
Variables are stored with the store command and referenced with ${variable_name}:
// Store a variable
{"command": "store", "target": "admin_user", "value": "username"}
// Use the variable
{"command": "type", "target": "xpath=//input[@id=\"username-field\"]", "value": "${username}"}
Common Variables
| Variable | Description |
|---|---|
${URL_root} | Base URL for the environment |
${username} | Login username |
${password} | Login password |
${hotp} | TOTP secret key |
${totp} | Generated TOTP code |
${mfa_link} | MFA redirect URL |
Authentication Flow Template
The tests use TOTP-based MFA authentication. Below is the standard login flow used across all test suites:
[
{"comment": "Open login page", "command": "open", "target": "${URL_root}/login/admin"},
{"comment": "Set window size", "command": "setWindowSize", "target": "1280x800"},
{"comment": "Store username", "command": "store", "target": "username_value", "value": "username"},
{"comment": "Store password", "command": "store", "target": "password_value", "value": "password"},
{"comment": "Store TOTP secret", "command": "store", "target": "TOTP_SECRET_HERE", "value": "hotp"},
{"comment": "Enter username", "command": "type", "target": "xpath=//input[@id=\"username-field\"]", "value": "${username}"},
{"comment": "Enter password", "command": "type", "target": "xpath=//input[@id=\"password-field\"]", "value": "${password}"},
{"comment": "Click submit", "command": "click", "target": "css=button[type=\"submit\"]"},
{"comment": "Capture MFA redirect URL", "command": "executeScript", "target": "return window.location.href", "value": "mfa_link"},
{"comment": "Go to TOTP generator", "command": "open", "target": "https://totp.danhersam.com/"},
{"comment": "Enter TOTP secret", "command": "type", "target": "css=input[placeholder=\"The secret key (in base-32 format)\"]", "value": "${hotp}"},
{"comment": "Wait for TOTP generation", "command": "pause", "target": "3000"},
{"comment": "Wait for token element", "command": "assertElementPresent", "target": "css=#token"},
{"comment": "Capture TOTP code", "command": "executeScript", "target": "const element = document.querySelector('#token');\nreturn element.textContent;", "value": "totp"},
{"comment": "Return to app", "command": "open", "target": "${mfa_link}"},
{"comment": "Enter TOTP code", "command": "type", "target": "xpath=//input[@name=\"totp_code\"]", "value": "${totp}"},
{"comment": "Submit MFA", "command": "click", "target": "css=button[type=\"submit\"]"}
]
Complete Test Template
{
"id": "test-uuid-here",
"name": "Test Name",
"commands": [
{
"id": "cmd-1-uuid",
"comment": "Open start URL",
"command": "open",
"target": "${URL_root}/page",
"targets": [],
"value": ""
},
{
"id": "cmd-2-uuid",
"comment": "Set window size",
"command": "setWindowSize",
"target": "1280x800",
"targets": [],
"value": ""
},
{
"id": "cmd-3-uuid",
"comment": "Click element",
"command": "click",
"target": "xpath=//button[@id=\"action-button\"]",
"targets": [],
"value": ""
},
{
"id": "cmd-4-uuid",
"comment": "Wait for result",
"command": "pause",
"target": "2000",
"targets": [],
"value": ""
},
{
"id": "cmd-5-uuid",
"comment": "Verify element present",
"command": "assertElementPresent",
"target": "xpath=//div[@class=\"success-message\"]",
"targets": [],
"value": ""
}
]
}
Complete Project Template
{
"id": "project-uuid-here",
"version": "2.0",
"name": "Project Name",
"url": "",
"urls": [],
"tests": [
{
"id": "test-1-uuid",
"name": "Test Case 1",
"commands": [
// Commands here
]
},
{
"id": "test-2-uuid",
"name": "Test Case 2",
"commands": [
// Commands here
]
}
]
}
Existing Tests
The current project includes 12 Selenium IDE tests (exported from Ghost Inspector):
| Test Name | Purpose |
|---|---|
| Audit | Test audit functionality |
| LJ Report | Test Levey-Jennings report |
| Outcomes Report | Test outcomes report generation |
| Runfile List | Test runfile list pagination |
| Runfile Report | Test runfile report |
| Runfile Report (Assay Summary) | Test assay summary view |
| Runfile Report (Outcome Summary) | Test outcome summary view |
| Runfile Report (Plate Map) | Test plate map visualization |
| Runfile Report (Quantification) | Test quantification data |
| Runfile Report (Westgards) | Test Westgard rules display |
| Trends Report | Test trends analysis |
| Upload Runs | Test run file upload |
Best Practices
- Use descriptive comments -- Every command should have a clear comment explaining its purpose.
- Use variables for credentials -- Never hardcode passwords in commands.
- Add waits appropriately -- Use
pauseorassertElementPresentbefore interactions with dynamically loaded elements. - Use stable selectors -- Prefer IDs and data attributes over class names, which are more likely to change.
- Generate unique UUIDs -- Each project, test, and command needs a unique ID.
- Test in isolation -- Each test should handle its own setup (login, navigation) without depending on state from other tests.
- Use XPath for complex selectors -- When CSS selectors are insufficient for targeting specific elements.