From 1138eceb65e27cd3f630ac57a8c996e8aba9177a Mon Sep 17 00:00:00 2001 From: bheemreddy-samsara Date: Sun, 2 Nov 2025 14:58:20 -0600 Subject: [PATCH] feat: add device.backgroundApp() helper Add backgroundApp() method to delegate to Appium's mobile: backgroundApp command. Allows sending apps to background for testing scenarios like state restoration and battery testing. --- .changeset/backgrounding-support.md | 5 ++++ src/device/index.ts | 25 +++++++++++++++++ src/tests/device.spec.ts | 42 +++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 .changeset/backgrounding-support.md create mode 100644 src/tests/device.spec.ts diff --git a/.changeset/backgrounding-support.md b/.changeset/backgrounding-support.md new file mode 100644 index 00000000..66f0972e --- /dev/null +++ b/.changeset/backgrounding-support.md @@ -0,0 +1,5 @@ +--- +"appwright": patch +--- + +Add `device.backgroundApp()` to delegate to Appium's `mobile: backgroundApp` command. \ No newline at end of file diff --git a/src/device/index.ts b/src/device/index.ts index 3087385b..6ad7c53b 100644 --- a/src/device/index.ts +++ b/src/device/index.ts @@ -274,6 +274,31 @@ export class Device { ]); } + /** + * Sends the currently running app to the background. + * + * @param seconds - Number of seconds to keep app in background. + * Use -1 to background indefinitely (until manually reactivated). + * If positive number, app returns to foreground after specified seconds. + * + * @example + * ```js + * // Background for 10 seconds then auto-return + * await device.backgroundApp(10); + * + * // Background indefinitely (for battery tests) + * await device.backgroundApp(-1); + * await device.pause(30 * 60 * 1000); // Wait 30 minutes + * await device.activateApp(); // Manually bring back + * ``` + */ + @boxedStep + async backgroundApp(seconds: number = -1): Promise { + await this.webDriverClient.executeScript("mobile: backgroundApp", [ + seconds, + ]); + } + /** * Retrieves text content from the clipboard of the mobile device. This is useful * after a "copy to clipboard" action has been performed. This returns base64 encoded string. diff --git a/src/tests/device.spec.ts b/src/tests/device.spec.ts new file mode 100644 index 00000000..442b144b --- /dev/null +++ b/src/tests/device.spec.ts @@ -0,0 +1,42 @@ +import { describe, test, expect, vi } from "vitest"; +//@ts-ignore +import { Client as WebDriverClient } from "webdriver"; +import playwrightTest from "@playwright/test"; +import { Device } from "../device"; + +// Override Playwright's test.step/info to work in Vitest environment +// so boxedStep decorator can execute without throwing. +(playwrightTest as unknown as { step: Function }).step = vi.fn( + async (_name: string, body: () => Promise) => await body(), +); +(playwrightTest as unknown as { info: () => undefined }).info = () => undefined; + +const createDevice = (executeScript = vi.fn()) => { + //@ts-ignore - providing partial WebDriver client for testing + const webDriverClient: WebDriverClient = { + executeScript, + }; + const device = new Device( + webDriverClient, + "com.example.app", + { expectTimeout: 1_000 }, + "emulator", + ); + return { device, executeScript }; +}; + +describe("Device", () => { + describe("backgroundApp", () => { + test("backgrounds indefinitely by default", async () => { + const { device, executeScript } = createDevice(); + await device.backgroundApp(); + expect(executeScript).toHaveBeenCalledWith("mobile: backgroundApp", [-1]); + }); + + test("backgrounds for given duration", async () => { + const { device, executeScript } = createDevice(); + await device.backgroundApp(30); + expect(executeScript).toHaveBeenCalledWith("mobile: backgroundApp", [30]); + }); + }); +});