Squish Test Scripting: Python, JavaScript, and Tcl for GUI Automation
Squish from Froglogic (now part of Qt Group) is one of the few GUI test automation tools that gives you real scripting flexibility without forcing you to use a specific language. Python, JavaScript, Perl, Ruby, and Tcl are all supported as scripting languages for Squish tests. The test logic is your code; Squish provides the API to drive the application under test and inspect its state. For teams automating desktop GUI applications — especially Qt, Java Swing, or cross-platform apps — this scripting model is one of Squish's core strengths.
How Scripting Works in Squish
Squish runs as a client-server system. The Squish Server (squishserver) attaches to the application under test and controls it. The test script runs in the Squish Runner (squishrunner) and communicates with the server to drive application behavior and inspect UI state.
From the script's perspective, this is transparent. You import the Squish API module, call functions to find objects, interact with them, and verify state. The communication overhead is hidden. Your test script reads like application interaction code, not network protocol handling.
A minimal Python test looks like:
import squish
import test
def main():
startApplication("myapp")
# Find a button by its object name
ok_button = squish.findObject(squish.waitForObject(
{"type": "QPushButton", "text": "OK", "visible": True}
))
# Click it
squish.clickButton(ok_button)
# Verify a label shows expected text
label = squish.waitForObject({"type": "QLabel", "objectName": "statusLabel"})
test.compare(squish.object.properties(label)["text"], "Operation complete")The test module provides assertion functions: test.compare, test.verify, test.warning, test.fail. These integrate with Squish's result reporting — assertions don't raise exceptions; they record pass/fail in the test log.
The Squish API Surface
The Squish API provides functions for every category of GUI interaction:
Object finding: findObject, waitForObject, findAllObjects. These take an object lookup specification (OLS) — a dictionary of property criteria — and return a reference to the matching object in the running application.
Mouse and keyboard: clickButton, mouseClick, type, pressKey, keyClick. These operate on found objects.
Property access: object.properties(obj) returns a dictionary of the object's properties. Individual properties can be accessed with object.property(obj, "propertyName").
Application control: startApplication, attachToApplication, closeApplication. Squish can launch the application itself or attach to an already-running process.
Image verification: test.vp("VerificationPointName") for visual verification points — screenshot comparisons against stored baselines. Visual verification is optional; most scripted tests use property-based assertions.
Drag and drop, gestures: drag, flick, pinch for applications with complex gesture requirements (particularly mobile application testing).
The API is consistent across all supported scripting languages. A test written in Python uses the same function names and patterns as one written in JavaScript. Porting between languages is mostly syntax translation, not API translation.
Object Lookup Specifications
Finding the right object is the critical skill in Squish scripting. The Object Lookup Specification (OLS) is a dictionary of property-value pairs that Squish uses to locate an object in the running application's object hierarchy.
For Qt applications, properties include type (the Qt class name), objectName (if set by developers), text, title, visible, and any custom properties exposed by the class. A well-specified lookup that uses objectName is fast and resilient to UI layout changes. A lookup that relies only on visual properties like text can break when labels change.
Squish's IDE includes an Object Spy that shows the running application's object hierarchy and available properties in real time. You use the Object Spy during test development to identify the right properties for reliable lookup.
For applications where developers have set objectName properties on UI components (a good practice that aids both testing and debugging), lookups are straightforward. For applications with no objectName attributes, you rely on other properties and potentially on container hierarchy (finding a button within a specific dialog, for example).
Writing Reusable Test Functions
Squish organizes tests into test suites. Each suite has a suite-level scripts directory where you put shared helper functions and data. Individual test scripts can import from the suite scripts, creating a library of reusable operations.
A common pattern is to create page-object equivalents for each screen of the application:
# suite/scripts/login_screen.py
def perform_login(username, password):
username_field = squish.waitForObject(
{"type": "QLineEdit", "objectName": "usernameField"}
)
squish.type(username_field, username)
password_field = squish.waitForObject(
{"type": "QLineEdit", "objectName": "passwordField"}
)
squish.type(password_field, password)
squish.clickButton(squish.waitForObject(
{"type": "QPushButton", "text": "Log In"}
))
# Wait for the main window to appear
squish.waitForObject({"type": "MainWindow", "visible": True})Individual test scripts import and call this function:
# tst_dashboard_access/test.py
import names
source(findFile("scripts", "login_screen.py"))
def main():
startApplication("myapp")
perform_login("testuser", "testpassword")
# now test dashboard functionalityThis pattern keeps test logic readable and reduces duplication. When the login screen changes, you update one function rather than every test that performs login.
Debugging with the Squish IDE
The Squish IDE (an Eclipse-based environment) provides a debugger that connects to running test scripts. You can set breakpoints in your test code, step through execution line by line, inspect variable values, and use the Object Spy to examine application state mid-execution.
This is a significant advantage over tools where test execution is opaque. When a Squish test fails because an object can't be found, you can pause execution just before the failing lookup and use the Object Spy to examine what objects are actually present in the application at that moment. This usually reveals whether the UI is in an unexpected state, whether the lookup properties are wrong, or whether a timing issue caused the object not to be ready yet.
The debugger supports all Squish scripting languages. The IDE also includes a script recorder that captures user interactions as script code — useful for getting started with a new screen, though the recorded code typically needs cleanup before use in a maintainable test.
Choosing Between Python, JavaScript, and Tcl
Python is the most common choice for new Squish projects. The readability, the ecosystem of support libraries (for data manipulation, file handling, reporting), and the widespread familiarity of Python in QA teams make it the practical default. Most Squish examples in documentation use Python.
JavaScript is a good choice when the development team primarily works in JavaScript/TypeScript and test maintenance is shared with developers. The scripting syntax is familiar to web developers. If your Qt application is a QML/JavaScript application, there's additional coherence in using JavaScript for tests.
Tcl is Squish's oldest supported language and retains a user base in organizations that have had Squish installations for a long time. Tcl is a capable language for test scripting but is not a common choice for new projects. If you're inheriting a Tcl-based Squish suite, it's worth evaluating whether migrating to Python is worthwhile — Squish can run different scripts in different languages within the same suite, so migration can be incremental.
Perl and Ruby are available but rarely chosen for new projects. They were more commonly used historically; current projects almost universally use Python or JavaScript.
Script Organization Best Practices
Large Squish test suites benefit from explicit organization:
- Group related tests into test suites by feature or application area
- Keep suite-level scripts focused on reusable helpers, not on test logic
- Use
names.py(Squish's symbolic name file) to store object lookup specifications rather than inline dictionaries — this creates one place to update selectors when the UI changes - Keep individual test scripts short; extract any sequence that appears more than once into a helper function
- Use test data files (CSV, Excel, or database) for data-driven tests rather than hardcoded values in scripts
Squish's test result reporter captures pass/fail at the individual assertion level. Investing in descriptive test messages for test.compare calls (test.compare(actual, expected, "Status label shows completion message after save")) makes failure reports actionable without requiring reproduction of the failure.