E2E testing for
smart TVs.
TypeScript. Off-device. Over HTTP. No Appium, no Selenium, no Java.
Your tests run in Node and talk to the device on port 8060.
npm install @danecodes/uncle-jesse-core @danecodes/uncle-jesse-roku @danecodes/uncle-jesse-test Feels like Playwright.
Built for the living room.
If you've written web E2E tests, you already know the API. Query elements, assert state, navigate with D-pad input. Uncle Jesse handles the Roku-specific plumbing.
const tv = new RokuAdapter({
ip: '192.168.1.100',
devPassword: 'rokudev',
});
await tv.connect();
await tv.launchApp('dev');
// CSS-like selectors on SceneGraph
const grid = await tv.$('HomeScreen RowList');
const title = await tv.$('Label#screenTitle');
// Navigate and assert
await tv.press('right', { times: 3 });
await tv.select();
const focused = await tv.getFocusedElement();
expect(focused?.getAttribute('title'))
.toBe('My List'); Everything you need to test a TV app.
CSS-Like Selectors
Query SceneGraph nodes with familiar syntax. HomeScreen RowList, #title, Label[text="Home"].
LiveElement
Persistent element references that re-query the device on each call. Chain selectors, actions, and assertions.
focusPath
Chainable D-pad navigation builder. Press keys, assert focus, collect all failures. Visual replay with screenshots.
Page Objects
BasePage and BaseComponent — the same pattern used in production Roku test suites. Drop-in migration from Appium.
Multi-Device
DevicePool manages parallel test execution across multiple Roku devices. Acquire, test, release.
CTRF Reports
Generate Common Test Reporting Format output for CI dashboards, Databricks, and cross-team analytics.
Visual Replay
Record screenshots at each focusPath step. Output a self-contained HTML debugger with scrubber and tree view.
Log Capture
Stream and parse BrightScript console output. Catch errors, crashes, and backtraces as structured data.
Mock Server
Deterministic test data with @danecodes/roku-mock. Manage scenarios, verify API calls, inject state.
const result = await focusPath(tv)
.press('right')
.expectFocus('[title="featured-2"]')
.press('right')
.expectFocus('[title="featured-3"]')
.press('down')
.expectFocus('[title="recent-2"]')
.verify();
expect(result.passed).toBe(true);
// With visual replay recording
const recorded = await focusPath(tv, {
record: true,
testName: 'grid-nav',
}).press('right')
.expectFocus('[title="featured-2"]')
.verify();
await saveReplay(recorded.replay, './results'); focusPath: test D-pad navigation in one chain.
Press keys, assert where focus lands, collect all failures instead of stopping at the first one. Enable record: true to capture screenshots and tree snapshots at every step — outputs a self-contained HTML replay debugger.
Every step waits for focus to stabilize before checking. No flaky timing hacks.
Architecture
Packages
| Package | Description |
|---|---|
@danecodes/uncle-jesse-core | TVDevice, LiveElement, BasePage, BaseComponent, SelectorEngine, RegistryState, DevicePool |
@danecodes/uncle-jesse-roku | Roku adapter, media player, log capture via roku-ecp and roku-log |
@danecodes/uncle-jesse-test | focusPath, vitest matchers, vitest plugin, replay debugger |
uncle-jesse | CLI (test, discover, sideload) and reporters (console, JUnit, CTRF) |
Stop pressing buttons manually.
Get started in five minutes. Roku first, with other platforms planned.