Choose a framework integration
You do not need an integration to test a terminal program. Start with the black-box API when text, cells, keys, resize, or process behavior are enough.
Add an integration when a test should identify application controls by role, label, state, or framework identity:
const save = app.getByRole('button', { name: 'Save' });await expect(save).toBeAttached();Install the integration from the same Termwright release as the test package. For example, Termwright 0.4.1 requires the 0.4.1 npm, Python, Go, and Rust integration packages. Mixing releases is unsupported because their semantic protocol changes together.
Supported frameworks
Section titled “Supported frameworks”| Framework | Tested versions | Runtime | Semantic locators | Viewport visibility | Click by locator |
|---|---|---|---|---|---|
| Ink | 7.1.1 | Node.js ^22.0.0 || ^24.0.0; Bun >=1.2.15 | Yes | Yes | Requires application pointer setup |
| OpenTUI | 0.5.3, 0.5.4, 0.5.6, 0.5.7, 0.5.8, 0.5.9, 0.5.10 | Bun >=1.2.15; Node.js ^22.0.0 || ^24.0.0 | Yes | Yes | Yes |
| Textual | 8.2.8 | CPython >=3.9 | Yes | Yes | Yes |
| tview | v0.42.0 | Go >=1.24; Node.js ^22.0.0 || ^24.0.0 | Yes | No | Requires application pointer setup |
| Ratatui | 0.30.2 | Rust >=1.88; Cargo stable | Yes | No | Requires application pointer setup |
| Bubble Tea / Bubbles | v1.3.10, v2.0.8, v2.0.9 | Go >=1.24; Node.js ^22.0.0 || ^24.0.0 | Yes | No | Requires application pointer setup |
The version cells come directly from Termwright’s compatibility registry. Read the framework guide before installing an integration: JavaScript frameworks use a runtime wrapper, Python uses a probe launcher, and Go and Rust integrations prepare an instrumented build. Every locator click also requires the application to enable terminal mouse reporting.
What the integration changes
Section titled “What the integration changes”An integration publishes a semantic tree alongside the terminal screen. Tests can then use:
- roles and accessible names;
- labels and relationships;
- focus, selected, checked, disabled, and framework-specific state when exposed;
- semantic snapshots; and
- geometry and pointer actions where listed in the table.
Input still goes through the terminal. Termwright does not call a component’s event handler to make a test pass.
What it does not infer
Section titled “What it does not infer”Decorated text that looks like [ Save ] is not automatically a button.
Likewise, a component’s layout rectangle does not prove that a mouse event will
reach it. The integration reports the information its framework retains;
unsupported information remains unavailable.
Some frameworks need annotations for application-specific names, roles, or stable identities. Prefer framework-native accessibility properties where they exist. An annotation can add application meaning, but it cannot override actual focus, clipping, or pointer routing.
Verify the setup
Section titled “Verify the setup”After following the framework guide, write one small semantic assertion:
const app = await terminal.launch({ command });
await app.waitForText('Permission required');await expect(app.getByRole('button', { name: 'Approve' })).toBeAttached();Open the Runner’s semantic tree if the locator fails. Installing a package is not enough when the framework also requires a wrapper or instrumented build.
Need a different framework?
Section titled “Need a different framework?”Use the black-box terminal API if screen behavior is sufficient. Integration authoring is maintained with the contributor documentation rather than this user setup path.
For exact version rules and framework-specific limitations, see the compatibility reference.