mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-05 13:29:44 +02:00
* fix(auth): autofocus OTP input on verification step The email-verification step renders the OTP input without focus, so users must click the field before typing the code. This is friction on every login, especially when switching accounts. Add `autoFocus` to the InputOTP so the cursor lands in the field as soon as the step mounts. Mirrors the existing email-step input and the mobile OTP component, both of which already autofocus. * test(web): polyfill document.elementFromPoint for input-otp in jsdom Autofocusing the OTP input makes input-otp run its focus-time DOM measurement, which calls document.elementFromPoint. jsdom doesn't implement it, so the web login test threw an unhandled error. packages/views/test/setup.ts already stubs this for the same reason; mirror the stub in the web test setup (which already stubs ResizeObserver for input-otp). * test(auth): assert OTP input autofocuses on verification step Guards the autofocus behavior: the test fails if the autoFocus prop is removed from the verification-step InputOTP. Lives in packages/views since it covers shared component behavior, mocking @multica/core.
49 lines
1.4 KiB
TypeScript
49 lines
1.4 KiB
TypeScript
import "@testing-library/jest-dom/vitest";
|
|
import { vi } from "vitest";
|
|
|
|
// jsdom doesn't provide ResizeObserver; stub it so components that rely on it
|
|
// (e.g. input-otp) can render in tests.
|
|
if (typeof globalThis.ResizeObserver === "undefined") {
|
|
globalThis.ResizeObserver = class ResizeObserver {
|
|
observe() {}
|
|
unobserve() {}
|
|
disconnect() {}
|
|
} as unknown as typeof ResizeObserver;
|
|
}
|
|
|
|
// jsdom doesn't implement elementFromPoint; input-otp uses it internally.
|
|
if (typeof document.elementFromPoint !== "function") {
|
|
document.elementFromPoint = () => null;
|
|
}
|
|
|
|
// jsdom 29 / Node.js 22+ may not provide a proper Web Storage API.
|
|
// Create a proper localStorage mock if methods are missing.
|
|
if (
|
|
typeof globalThis.localStorage === "undefined" ||
|
|
typeof globalThis.localStorage.getItem !== "function"
|
|
) {
|
|
const store: Record<string, string> = {};
|
|
const localStorageMock = {
|
|
getItem: vi.fn((key: string) => store[key] ?? null),
|
|
setItem: vi.fn((key: string, value: string) => {
|
|
store[key] = value;
|
|
}),
|
|
removeItem: vi.fn((key: string) => {
|
|
delete store[key];
|
|
}),
|
|
clear: vi.fn(() => {
|
|
for (const key of Object.keys(store)) {
|
|
delete store[key];
|
|
}
|
|
}),
|
|
get length() {
|
|
return Object.keys(store).length;
|
|
},
|
|
key: vi.fn((index: number) => Object.keys(store)[index] ?? null),
|
|
};
|
|
Object.defineProperty(globalThis, "localStorage", {
|
|
value: localStorageMock,
|
|
writable: true,
|
|
});
|
|
}
|