@lynx-js/kitten-lynx-test-infra
v0.1.2
Published
A testing framework executing the Lynx explorer Android application
Downloads
161
Readme
Kitten-Lynx (🐾 testing-library)
Kitten-Lynx is a Puppeteer-like / Playwright-like testing library. It is designed specifically for interacting with the Lynx browser engine and the Lynx Explorer Android application.
If you are an AI Agent (or a developer) reading this, this document is optimized to be as clear and straightforward as possible to help you write tests and understand the architecture without guessing.
🌟 What does it do?
Using the Chrome DevTools Protocol (CDP) over USB/ADB, kitten-lynx gives you the power to:
- Automatically open the Lynx Explorer app on an Android emulator or physical device.
- Navigate to
.lynx.bundleURLs. - Access the Lynx DOM (Document Object Model) tree.
- Find elements using CSS Selectors (e.g.
page.locator('#my-id')). - Read element styles and attributes.
- Simulate native touch gestures (like tapping on buttons).
🏗️ Architecture Explained (For Agents)
In standard Web Playwright/Puppeteer, you connect to a persistent browser WebSocket. Lynx is different.
- Stateless Connector: This library uses
@lynx-js/devtool-connectorwhich operates via Android Debug Bridge (ADB). It sends isolated Request/Response commands. There is no long-living socket. - Session Hopping: When you tell Lynx to navigate to a new URL, Lynx creates an entirely new debugging session.
Lynx.ts: Handles the physical device connection, force-stops the app, restarts it, and ensures the Master devtool switch is ON.KittenLynxView.ts: Represents a single "Page". When you callgoto(url), it sends the navigate command, and then intensely polls the ADB session list until it finds the new session matching your URL, and re-attaches to it.ElementNode.ts: Represents a physical tag (like<view>or<text>). Cached viaWeakRefto save memory. Uses native coordinate math viaDOM.getBoxModelto simulate real screen taps.
🚀 Quick Start Guide
Prerequisites
- You must have an Android Emulator or device running via
adb. - The Lynx Explorer APK must be installed (
adb install LynxExplorer.apk). - (In CI) Ensure your test runner can reach your local bundle dev server (you might need
adb reverse tcp:8080 tcp:8080).
Example Test Script
Here is the blueprint for a standard test written using kitten-lynx and vitest:
import { expect, test, beforeAll, afterAll } from 'vitest';
import { Lynx } from '@lynx-js/kitten-lynx-test-infra';
import type { KittenLynxView } from '@lynx-js/kitten-lynx-test-infra';
let lynx: Lynx;
let page: KittenLynxView;
// Setup: Connect to device
beforeAll(async () => {
// Connects to the first available ADB device and opens com.lynx.explorer
lynx = await Lynx.connect();
page = await lynx.newPage();
}, 60000); // Give ADB enough time to boot!
// Teardown: Clean up resources
afterAll(async () => {
await lynx.close();
});
test('Basic Navigation and Interaction', async () => {
// 1. Navigate to the bundle (Will poll until the session is found)
await page.goto('http://10.0.2.2:8080/dist/main.lynx.bundle');
// 2. Locate an element by CSS Selector
const button = await page.locator('#submit-btn');
expect(button).toBeDefined();
// 3. Read an attribute.
// (Note: 'id' maps internally to Lynx's 'idSelector')
const idValue = await button!.getAttribute('id');
expect(idValue).toBe('submit-btn');
// 4. Read computed CSS styles
const styles = await button!.computedStyleMap();
expect(styles.get('display')).toBe('flex');
// 5. Simulate a native tap
await button!.tap();
// 6. Assert DOM changes (re-query the new element)
const successText = await page.locator('.success-message');
expect(successText).toBeDefined();
}, 30000);⚠️ Known Gotchas & Pitfalls
If you are writing scripts and tests, memorize these rules:
goto()implies a Session Change: Afterpage.goto(), the old node IDs are dead. Always query elements after the navigation finishes.- Timeouts: Android emulators take time to boot. The devtool ADB bridge takes time to synchronize. Always set high timeouts for setup hooks (
beforeAll(..., 60000)). - No
App.openPagelocally: Lynx Explorer 3.6.0 does not supportApp.openPageproperly in some fallback layers.kitten-lynxfalls back to a Custom OpenCard event automatically. You do not need to worry about this, but do not be alarmed by terminal warnings. - Id Selector: Standard web writes
<view id="test">. Lynx internally usesidSelector="test". TheElementNode.getAttribute('id')handles this mapping automatically for you. Do not query'idSelector'directly. - DOM Snapshots: You can call
await page.content()to get a massive HTML-like string of the current Lynx DOM. This is extremely helpful for debugging what is actually rendering!
🛠️ Extending the Library
If you need to add a newly supported CDP command:
- Open
src/CDPChannel.ts. - Add the strictly-typed parameter and return shapes to the
Protocolinterface block at the top of the file. - Call
await this._channel.send('Domain.methodName', params)inKittenLynxVieworElementNode. - Run
pnpm run build && pnpm run testbefore committing.
