67 lines
1.9 KiB
TypeScript
67 lines
1.9 KiB
TypeScript
|
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||
|
|
import { rpc } from "./api";
|
||
|
|
import { cancelModelOAuthAttempt, finishModelOAuthAttempt, waitForModelOAuth } from "./model-auth";
|
||
|
|
|
||
|
|
vi.mock("./api", () => ({ rpc: vi.fn() }));
|
||
|
|
|
||
|
|
describe("mobile waitForModelOAuth", () => {
|
||
|
|
const mockRpc = vi.mocked(rpc);
|
||
|
|
|
||
|
|
beforeEach(() => {
|
||
|
|
mockRpc.mockReset();
|
||
|
|
});
|
||
|
|
|
||
|
|
it("stops polling when its screen loses focus", async () => {
|
||
|
|
mockRpc.mockResolvedValue({ status: "pending" });
|
||
|
|
const controller = new AbortController();
|
||
|
|
const polling = waitForModelOAuth("login-id", controller.signal);
|
||
|
|
|
||
|
|
await Promise.resolve();
|
||
|
|
expect(mockRpc).toHaveBeenCalledTimes(1);
|
||
|
|
controller.abort();
|
||
|
|
|
||
|
|
await expect(polling).rejects.toBeDefined();
|
||
|
|
expect(mockRpc).toHaveBeenCalledTimes(1);
|
||
|
|
});
|
||
|
|
|
||
|
|
it("returns readiness normally", async () => {
|
||
|
|
mockRpc.mockResolvedValue({ status: "ready" });
|
||
|
|
|
||
|
|
await expect(waitForModelOAuth("login-id")).resolves.toMatchObject({ status: "ready" });
|
||
|
|
expect(mockRpc).toHaveBeenCalledTimes(1);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe("mobile OAuth focus lifecycle", () => {
|
||
|
|
it("resets busy state on focus cleanup and protects a newer attempt", () => {
|
||
|
|
const ref = { current: null as AbortController | null };
|
||
|
|
let busy = false;
|
||
|
|
const reset = () => {
|
||
|
|
busy = false;
|
||
|
|
};
|
||
|
|
const startAttempt = () => {
|
||
|
|
const controller = new AbortController();
|
||
|
|
ref.current = controller;
|
||
|
|
busy = true;
|
||
|
|
return controller;
|
||
|
|
};
|
||
|
|
|
||
|
|
const first = startAttempt();
|
||
|
|
cancelModelOAuthAttempt(ref, reset);
|
||
|
|
|
||
|
|
expect(first.signal.aborted).toBe(true);
|
||
|
|
expect(ref.current).toBeNull();
|
||
|
|
expect(busy).toBe(false);
|
||
|
|
|
||
|
|
const second = startAttempt();
|
||
|
|
finishModelOAuthAttempt(ref, first, reset);
|
||
|
|
|
||
|
|
expect(ref.current).toBe(second);
|
||
|
|
expect(busy).toBe(true);
|
||
|
|
|
||
|
|
finishModelOAuthAttempt(ref, second, reset);
|
||
|
|
expect(ref.current).toBeNull();
|
||
|
|
expect(busy).toBe(false);
|
||
|
|
});
|
||
|
|
});
|