import { describe, expect, it } from "@effect/vitest"; import { openOAuthPopup, reserveOAuthPopup } from "./oauth-popup"; type OAuthPopupTestWindow = { readonly screenX: number; readonly screenY: number; readonly outerWidth: number; readonly outerHeight: number; readonly location: { readonly origin: string }; readonly addEventListener: () => void; readonly removeEventListener: () => void; readonly open: ( url: string, name: string, features: string, ) => { closed: boolean; close: () => void; opener?: unknown; location: { href: string } };}; type FakePopup = { closed: boolean; close: () => void; opener?: unknown; location: { href: string };}; describe("openOAuthPopup", () => { it("does not open unsupported OAuth endpoint URLs", async () => { let openFailed = false; const teardown = openOAuthPopup({ url: "javascript:alert(1)", popupName: "oauth", channelName: "oauth-channel", onResult: () => {}, onOpenFailed: () => { openFailed = true; }, }); teardown(); await new Promise<void>((resolve) => queueMicrotask(() => resolve())); expect(openFailed).toBe(true); }); it("opens supported OAuth URLs through a reserved popup with opener available", () => { let features = ""; let opened = ""; const popup: FakePopup = { closed: false, close: () => {}, location: { href: "" } }; const previousWindow = globalThis.window; const fakeWindow: OAuthPopupTestWindow = { screenX: 0, screenY: 0, outerWidth: 1200, outerHeight: 900, location: { origin: "https://app.example" }, addEventListener: () => {}, removeEventListener: () => {}, open: (url: string, _name: string, requestedFeatures: string) => { opened = url; features = requestedFeatures; return popup; }, }; Object.defineProperty(globalThis, "window", { configurable: true, value: fakeWindow, writable: true, }); const teardown = openOAuthPopup({ url: "https://auth.example/authorize", popupName: "oauth", channelName: "oauth-channel", onResult: () => {}, }); teardown(); Object.defineProperty(globalThis, "window", { configurable: true, value: previousWindow, writable: true, }); expect(opened).toBe("about:blank"); expect(popup.opener).toBeUndefined(); expect(popup.location.href).toBe("https://auth.example/authorize"); expect(features).toContain("popup=1"); expect(features).not.toContain("noopener"); expect(features).not.toContain("noreferrer"); }); it("can reserve the popup before an async authorization start", () => { let opened = ""; const popup: FakePopup = { closed: false, close: () => {}, location: { href: "" } }; const previousWindow = globalThis.window; const fakeWindow: OAuthPopupTestWindow = { screenX: 0, screenY: 0, outerWidth: 1200, outerHeight: 900, location: { origin: "https://app.example" }, addEventListener: () => {}, removeEventListener: () => {}, open: (url: string) => { opened = url; return popup; }, }; Object.defineProperty(globalThis, "window", { configurable: true, value: fakeWindow, writable: true, }); const reservedPopup = reserveOAuthPopup({ popupName: "oauth" }); const teardown = openOAuthPopup({ url: "https://auth.example/authorize", popupName: "oauth", channelName: "oauth-channel", reservedPopup: reservedPopup ?? undefined, onResult: () => {}, }); teardown(); Object.defineProperty(globalThis, "window", { configurable: true, value: previousWindow, writable: true, }); expect(opened).toBe("about:blank"); expect(reservedPopup).not.toBeNull(); expect(popup.opener).toBeUndefined(); expect(popup.location.href).toBe("https://auth.example/authorize"); }); it("opens HTTP authorization URLs returned by local flows", () => { let opened = ""; const popup: FakePopup = { closed: false, close: () => {}, location: { href: "" } }; const previousWindow = globalThis.window; const fakeWindow: OAuthPopupTestWindow = { screenX: 0, screenY: 0, outerWidth: 1200, outerHeight: 900, location: { origin: "http://127.0.0.1:4000" }, addEventListener: () => {}, removeEventListener: () => {}, open: (url: string) => { opened = url; return popup; }, }; Object.defineProperty(globalThis, "window", { configurable: true, value: fakeWindow, writable: true, }); const teardown = openOAuthPopup({ url: "http://example.com/authorize", popupName: "oauth", channelName: "oauth-channel", onResult: () => {}, }); teardown(); Object.defineProperty(globalThis, "window", { configurable: true, value: previousWindow, writable: true, }); expect(opened).toBe("about:blank"); expect(popup.location.href).toBe("http://example.com/authorize"); }); it("can disable popup.closed polling for providers with strict opener policies", () => { let closedCalled = false; let intervalStarted = false; const popup: FakePopup = { closed: true, close: () => {}, location: { href: "" } }; const previousWindow = globalThis.window; const previousSetInterval = globalThis.setInterval; const fakeWindow: OAuthPopupTestWindow = { screenX: 0, screenY: 0, outerWidth: 1200, outerHeight: 900, location: { origin: "https://app.example" }, addEventListener: () => {}, removeEventListener: () => {}, open: () => popup, }; Object.defineProperty(globalThis, "window", { configurable: true, value: fakeWindow, writable: true, }); Object.defineProperty(globalThis, "setInterval", { configurable: true, value: () => { intervalStarted = true; return 1; }, writable: true, }); const teardown = openOAuthPopup({ url: "https://auth.example/authorize", popupName: "oauth", channelName: "oauth-channel", closedPollMs: null, onResult: () => {}, onClosed: () => { closedCalled = true; }, }); teardown(); Object.defineProperty(globalThis, "window", { configurable: true, value: previousWindow, writable: true, }); Object.defineProperty(globalThis, "setInterval", { configurable: true, value: previousSetInterval, writable: true, }); expect(intervalStarted).toBe(false); expect(closedCalled).toBe(false); });});
import { describe, expect, it } from "@effect/vitest";
import { openOAuthPopup, reserveOAuthPopup } from "./oauth-popup";
type OAuthPopupTestWindow = {
readonly screenX: number;
readonly screenY: number;
readonly outerWidth: number;
readonly outerHeight: number;
readonly location: { readonly origin: string };
readonly addEventListener: () => void;
readonly removeEventListener: () => void;
readonly open: (
url: string,
name: string,
features: string,
) => { closed: boolean; close: () => void; opener?: unknown; location: { href: string } };
};
type FakePopup = {
closed: boolean;
close: () => void;
opener?: unknown;
location: { href: string };
};
describe("openOAuthPopup", () => {
it("does not open unsupported OAuth endpoint URLs", async () => {
let openFailed = false;
const teardown = openOAuthPopup({
url: "javascript:alert(1)",
popupName: "oauth",
channelName: "oauth-channel",
onResult: () => {},
onOpenFailed: () => {
openFailed = true;
},
});
teardown();
await new Promise<void>((resolve) => queueMicrotask(() => resolve()));
expect(openFailed).toBe(true);
});
it("opens supported OAuth URLs through a reserved popup with opener available", () => {
let features = "";
let opened = "";
const popup: FakePopup = { closed: false, close: () => {}, location: { href: "" } };
const previousWindow = globalThis.window;
const fakeWindow: OAuthPopupTestWindow = {
screenX: 0,
screenY: 0,
outerWidth: 1200,
outerHeight: 900,
location: { origin: "https://app.example" },
addEventListener: () => {},
removeEventListener: () => {},
open: (url: string, _name: string, requestedFeatures: string) => {
opened = url;
features = requestedFeatures;
return popup;
},
};
Object.defineProperty(globalThis, "window", {
configurable: true,
value: fakeWindow,
writable: true,
});
const teardown = openOAuthPopup({
url: "https://auth.example/authorize",
popupName: "oauth",
channelName: "oauth-channel",
onResult: () => {},
});
teardown();
Object.defineProperty(globalThis, "window", {
configurable: true,
value: previousWindow,
writable: true,
});
expect(opened).toBe("about:blank");
expect(popup.opener).toBeUndefined();
expect(popup.location.href).toBe("https://auth.example/authorize");
expect(features).toContain("popup=1");
expect(features).not.toContain("noopener");
expect(features).not.toContain("noreferrer");
});
it("can reserve the popup before an async authorization start", () => {
let opened = "";
const popup: FakePopup = { closed: false, close: () => {}, location: { href: "" } };
const previousWindow = globalThis.window;
const fakeWindow: OAuthPopupTestWindow = {
screenX: 0,
screenY: 0,
outerWidth: 1200,
outerHeight: 900,
location: { origin: "https://app.example" },
addEventListener: () => {},
removeEventListener: () => {},
open: (url: string) => {
opened = url;
return popup;
},
};
Object.defineProperty(globalThis, "window", {
configurable: true,
value: fakeWindow,
writable: true,
});
const reservedPopup = reserveOAuthPopup({ popupName: "oauth" });
const teardown = openOAuthPopup({
url: "https://auth.example/authorize",
popupName: "oauth",
channelName: "oauth-channel",
reservedPopup: reservedPopup ?? undefined,
onResult: () => {},
});
teardown();
Object.defineProperty(globalThis, "window", {
configurable: true,
value: previousWindow,
writable: true,
});
expect(opened).toBe("about:blank");
expect(reservedPopup).not.toBeNull();
expect(popup.opener).toBeUndefined();
expect(popup.location.href).toBe("https://auth.example/authorize");
});
it("opens HTTP authorization URLs returned by local flows", () => {
let opened = "";
const popup: FakePopup = { closed: false, close: () => {}, location: { href: "" } };
const previousWindow = globalThis.window;
const fakeWindow: OAuthPopupTestWindow = {
screenX: 0,
screenY: 0,
outerWidth: 1200,
outerHeight: 900,
location: { origin: "http://127.0.0.1:4000" },
addEventListener: () => {},
removeEventListener: () => {},
open: (url: string) => {
opened = url;
return popup;
},
};
Object.defineProperty(globalThis, "window", {
configurable: true,
value: fakeWindow,
writable: true,
});
const teardown = openOAuthPopup({
url: "http://example.com/authorize",
popupName: "oauth",
channelName: "oauth-channel",
onResult: () => {},
});
teardown();
Object.defineProperty(globalThis, "window", {
configurable: true,
value: previousWindow,
writable: true,
});
expect(opened).toBe("about:blank");
expect(popup.location.href).toBe("http://example.com/authorize");
});
it("can disable popup.closed polling for providers with strict opener policies", () => {
let closedCalled = false;
let intervalStarted = false;
const popup: FakePopup = { closed: true, close: () => {}, location: { href: "" } };
const previousWindow = globalThis.window;
const previousSetInterval = globalThis.setInterval;
const fakeWindow: OAuthPopupTestWindow = {
screenX: 0,
screenY: 0,
outerWidth: 1200,
outerHeight: 900,
location: { origin: "https://app.example" },
addEventListener: () => {},
removeEventListener: () => {},
open: () => popup,
};
Object.defineProperty(globalThis, "window", {
configurable: true,
value: fakeWindow,
writable: true,
});
Object.defineProperty(globalThis, "setInterval", {
configurable: true,
value: () => {
intervalStarted = true;
return 1;
},
writable: true,
});
const teardown = openOAuthPopup({
url: "https://auth.example/authorize",
popupName: "oauth",
channelName: "oauth-channel",
closedPollMs: null,
onResult: () => {},
onClosed: () => {
closedCalled = true;
},
});
teardown();
Object.defineProperty(globalThis, "window", {
configurable: true,
value: previousWindow,
writable: true,
});
Object.defineProperty(globalThis, "setInterval", {
configurable: true,
value: previousSetInterval,
writable: true,
});
expect(intervalStarted).toBe(false);
expect(closedCalled).toBe(false);
});
});