mirror of
https://github.com/software-mansion/argent.git
synced 2026-09-14 19:27:14 +08:00
837d088744
This PR adds tests for #148. ## Summary Moves the Android emulator branch's test coverage out of #148 so that PR can be reviewed without the test churn. This branch adds the test files back on top of the (now test-stripped) base branch. Tests inseparable from source changes (`describe-tool`, `workspace-reader`, `workspace-reader-integration`) and the `boot-simulator.test.ts` deletion stayed on #148 - base PR's CI passes on its own. ## Test plan - [x] `npx tsc --build` — clean - [x] `npx prettier --check .` — clean - [x] `npm test --workspaces --if-present` — 585/585 tool-server tests pass; all other workspaces green --------- Co-authored-by: Paweł Fornagiel <pawel.fornagiel2@gmail.com>
76 lines
3.1 KiB
TypeScript
76 lines
3.1 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
|
|
const execFileMock = vi.fn();
|
|
|
|
vi.mock("node:child_process", async () => {
|
|
const actual = await vi.importActual<typeof import("node:child_process")>("node:child_process");
|
|
return {
|
|
...actual,
|
|
execFile: (
|
|
cmd: string,
|
|
args: readonly string[],
|
|
opts: unknown,
|
|
cb?: (err: Error | null, out: { stdout: string; stderr: string }) => void
|
|
) => {
|
|
const callback = typeof opts === "function" ? opts : cb!;
|
|
const options = typeof opts === "function" ? undefined : opts;
|
|
const result = execFileMock(cmd, args, options);
|
|
if (result instanceof Error) {
|
|
// Mirror execFile's actual rejection contract: stderr/stdout are
|
|
// attached to the error object so describeAdbFailure can read them.
|
|
const e = result as Error & { stderr?: string; stdout?: string };
|
|
callback(e, { stdout: e.stdout ?? "", stderr: e.stderr ?? "" });
|
|
} else callback(null, result ?? { stdout: "", stderr: "" });
|
|
},
|
|
};
|
|
});
|
|
|
|
// `runAdb` resolves adb to an absolute path before spawning. Stub the
|
|
// resolver to return the bare name so existing `cmd === "adb"` mocks fire.
|
|
vi.mock("../src/utils/android-binary", () => ({
|
|
resolveAndroidBinary: vi.fn(async (name: "adb" | "emulator") => name),
|
|
__resetAndroidBinaryCacheForTesting: () => {},
|
|
}));
|
|
|
|
import { waitForBootCompleted } from "../src/utils/adb";
|
|
|
|
beforeEach(() => {
|
|
execFileMock.mockReset();
|
|
});
|
|
|
|
/**
|
|
* `isTerminalAdbError` checks for the literal substring "device not found",
|
|
* but adb's actual stderr is `error: device 'emulator-5554' not found` —
|
|
* the serial appears between "device" and "not found", so the substring
|
|
* match never fires. Result: when a device drops off PATH mid-boot,
|
|
* `waitForBootCompleted` keeps spinning until the full timeoutMs elapses
|
|
* (default 120 s) instead of failing fast with the actionable error.
|
|
*
|
|
* Expected: the function should detect the terminal state and throw on
|
|
* the first failed poll (well before timeoutMs).
|
|
*/
|
|
describe("isTerminalAdbError matches adb's real `device 'X' not found` format", () => {
|
|
it("waitForBootCompleted should fail fast when adb says \"device 'X' not found\"", async () => {
|
|
execFileMock.mockImplementation((cmd: string, args: string[]) => {
|
|
if (cmd === "adb" && args[0] === "-s" && args[2] === "shell") {
|
|
const err = new Error("Command failed") as Error & { stderr?: string };
|
|
err.stderr = "error: device 'emulator-5554' not found";
|
|
return err;
|
|
}
|
|
return new Error("unexpected call");
|
|
});
|
|
|
|
const start = Date.now();
|
|
// Use a small budget so the test doesn't take 2 minutes; the bug
|
|
// produces a full-timeoutMs hang regardless of size.
|
|
await expect(waitForBootCompleted("emulator-5554", 4_000)).rejects.toThrow(
|
|
/terminal state|device.*not found/i
|
|
);
|
|
const elapsed = Date.now() - start;
|
|
// Fail-fast path: throw fires after the first failed poll (< 1 s).
|
|
// Bug path: loop spins until the deadline (~timeoutMs).
|
|
// Anything ≥ 3 s on the 4 s budget proves the bug.
|
|
expect(elapsed).toBeLessThan(2_500);
|
|
}, 8_000);
|
|
});
|