Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions packages/driver-mobilecli/src/driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,23 @@ export class MobilecliDriver implements MobilewrightDriver {
await this.call('device.io.button', { button });
}

async dismissKeyboard(): Promise<void> {
const platform = this.requireSession().platform;

// Only dismiss if a text input is currently focused — otherwise the
// dismiss action (BACK / Done) could navigate back or submit a form.
const roots = await this.getViewHierarchy();
if (!focusedTextInputExists(roots)) {
return;
}

if (platform === 'android') {
await this.pressKeys(['back']);
} else {
await this.pressKeys(['Done']);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

// ─── Screen Operations ───────────────────────────────────────

async screenshot(opts?: ScreenshotOptions): Promise<Buffer> {
Expand Down Expand Up @@ -621,3 +638,21 @@ export class MobilecliDriver implements MobilewrightDriver {
return this.session;
}
}

/** Recursively scan for a focused text-input element. Returns true when found. */
function focusedTextInputExists(nodes: ViewNode[]): boolean {
for (const node of nodes) {
if (node.isFocused && isTextInputType(node.type)) {
return true;
}
if (node.children.length > 0 && focusedTextInputExists(node.children)) {
return true;
}
}
return false;
}

function isTextInputType(type: string): boolean {
const lower = type.toLowerCase();
return lower.includes('text') || lower.includes('edit') || lower.includes('search');
}
35 changes: 35 additions & 0 deletions packages/driver-mobilenext/src/driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,23 @@ export class MobileNextDriver implements MobilewrightDriver {
await this.call('device.io.button', { button });
}

async dismissKeyboard(): Promise<void> {
const platform = this.requireSession().platform;

// Only dismiss if a text input is currently focused — otherwise the
// dismiss action (BACK / Done) could navigate back or submit a form.
const roots = await this.getViewHierarchy();
if (!focusedTextInputExists(roots)) {
return;
}

if (platform === 'android') {
await this.pressKeys(['back']);
} else {
await this.pressKeys(['Done']);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

// ─── Screen ─────────────────────────────────────────────────

async screenshot(opts?: ScreenshotOptions): Promise<Buffer> {
Expand Down Expand Up @@ -594,3 +611,21 @@ export class MobileNextDriver implements MobilewrightDriver {
return this.session;
}
}

/** Recursively scan for a focused text-input element. Returns true when found. */
function focusedTextInputExists(nodes: ViewNode[]): boolean {
for (const node of nodes) {
if (node.isFocused && isTextInputType(node.type)) {
return true;
}
if (node.children.length > 0 && focusedTextInputExists(node.children)) {
return true;
}
}
return false;
}

function isTextInputType(type: string): boolean {
const lower = type.toLowerCase();
return lower.includes('text') || lower.includes('edit') || lower.includes('search');
}
6 changes: 5 additions & 1 deletion packages/mobilewright-core/src/locator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,10 +180,14 @@ export class Locator {
return this._step('locator.clear()', () => this._tapAndClear(opts?.timeout));
}

async fill(text: string, opts?: { timeout?: number }): Promise<void> {
async fill(text: string, opts?: { timeout?: number; dismissKeyboard?: boolean }): Promise<void> {
return this._step(`locator.fill(${JSON.stringify(text)})`, async () => {
await this._tapAndClear(opts?.timeout);
await this.driver.typeText(text);
const dismiss = opts?.dismissKeyboard ?? true;
if (dismiss) {
await this.driver.dismissKeyboard?.();
}
});
}

Expand Down
2 changes: 2 additions & 0 deletions packages/protocol/src/driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ export interface MobilewrightDriver {
gesture(gestures: GestureSequence): Promise<void>;
/** Press a hardware button (e.g. home, back, volume). */
pressButton(button: HardwareButton): Promise<void>;
/** Dismiss the soft keyboard if it is currently open. Optional — drivers that don't support it omit it. */
dismissKeyboard?(): Promise<void>;

// Screen
/** Capture a screenshot of the device screen as a PNG buffer. */
Expand Down