Skip to content

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.

FrameworkTested versionsRuntimeSemantic locatorsViewport visibilityClick by locator
Ink7.1.1Node.js ^22.0.0 || ^24.0.0; Bun >=1.2.15YesYesRequires application pointer setup
OpenTUI0.5.3, 0.5.4, 0.5.6, 0.5.7, 0.5.8, 0.5.9, 0.5.10Bun >=1.2.15; Node.js ^22.0.0 || ^24.0.0YesYesYes
Textual8.2.8CPython >=3.9YesYesYes
tviewv0.42.0Go >=1.24; Node.js ^22.0.0 || ^24.0.0YesNoRequires application pointer setup
Ratatui0.30.2Rust >=1.88; Cargo stableYesNoRequires application pointer setup
Bubble Tea / Bubblesv1.3.10, v2.0.8, v2.0.9Go >=1.24; Node.js ^22.0.0 || ^24.0.0YesNoRequires 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.

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.

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.

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.

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.