star-chart-search-enhancer/tests/popup-entry.test.ts

189 lines
4.8 KiB
TypeScript

import { JSDOM } from "jsdom";
import { beforeEach, describe, expect, test, vi } from "vitest";
import { bootPopup } from "../src/popup/index";
describe("popup-entry", () => {
let dom: JSDOM;
beforeEach(() => {
dom = new JSDOM("<!doctype html><html><body></body></html>");
});
test("renders a sign-in button when unauthenticated", async () => {
dom.window.document.body.innerHTML = "<main id='app'></main>";
await bootPopup({
document: dom.window.document,
sendMessage: vi.fn(async () => ({
ok: true,
type: "auth:state",
value: { isAuthenticated: false }
}))
});
expect(dom.window.document.querySelector("button")?.textContent).toContain(
"登录"
);
});
test("renders the dev auth panel when enabled", async () => {
dom.window.document.body.innerHTML = "<main id='app'></main>";
await bootPopup({
config: { enableDevAuthPanel: true },
document: dom.window.document,
sendMessage: vi.fn(async () => ({
ok: true,
type: "auth:state",
value: {
accessTokenExpiresAt: 1700000000000,
isAuthenticated: true,
resource: "https://api.example.test",
scopes: ["openid", "profile"],
tokenAvailable: true,
userInfo: { email: "dev@example.com", name: "Dev" }
}
}))
});
expect(dom.window.document.body.textContent).toContain("resource");
expect(dom.window.document.body.textContent).toContain("token");
});
test("renders a protected api test button in the dev panel", async () => {
dom.window.document.body.innerHTML = "<main id='app'></main>";
await bootPopup({
config: { enableDevAuthPanel: true },
document: dom.window.document,
sendMessage: vi.fn(async () => ({
ok: true,
type: "auth:state",
value: {
isAuthenticated: true,
tokenAvailable: true
}
}))
});
expect(
dom.window.document.querySelector('[data-popup-test-protected-api="button"]')
).not.toBeNull();
});
test("clicking the dev button runs the protected api client and prints the result", async () => {
const fetchProtectedApi = vi.fn(async () => ({
message: "authorized",
ok: true,
source: "mock-protected-api"
}));
const sendMessage = vi.fn(async () => ({
ok: true,
type: "auth:state",
value: {
isAuthenticated: true,
tokenAvailable: true
}
}));
dom.window.document.body.innerHTML = "<main id='app'></main>";
await bootPopup({
config: { enableDevAuthPanel: true },
document: dom.window.document,
fetchProtectedApi,
sendMessage
});
(
dom.window.document.querySelector(
'[data-popup-test-protected-api="button"]'
) as HTMLButtonElement | null
)?.click();
await Promise.resolve();
expect(fetchProtectedApi).toHaveBeenCalledTimes(1);
expect(dom.window.document.body.textContent).toContain("authorized");
expect(dom.window.document.body.textContent).toContain("mock-protected-api");
});
test("clicking sign-out sends the auth:sign-out message", async () => {
const sendMessage = vi
.fn()
.mockResolvedValueOnce({
ok: true,
type: "auth:state",
value: {
isAuthenticated: true,
userInfo: { email: "dev@example.com", name: "Dev" }
}
})
.mockResolvedValueOnce({
ok: true,
type: "auth:ack"
})
.mockResolvedValueOnce({
ok: true,
type: "auth:state",
value: {
isAuthenticated: false
}
});
dom.window.document.body.innerHTML = "<main id='app'></main>";
await bootPopup({
document: dom.window.document,
sendMessage
});
(
dom.window.document.querySelector('[data-popup-sign-out="button"]') as
| HTMLButtonElement
| null
)?.click();
await Promise.resolve();
expect(sendMessage).toHaveBeenCalledWith({ type: "auth:sign-out" });
});
test("shows the auth error when sign-in fails", async () => {
const sendMessage = vi
.fn()
.mockResolvedValueOnce({
ok: true,
type: "auth:state",
value: {
isAuthenticated: false
}
})
.mockResolvedValueOnce({
error: "redirect_uri_mismatch",
ok: false,
type: "auth:error"
});
dom.window.document.body.innerHTML = "<main id='app'></main>";
await bootPopup({
document: dom.window.document,
sendMessage
});
(
dom.window.document.querySelector('[data-popup-sign-in="button"]') as
| HTMLButtonElement
| null
)?.click();
await Promise.resolve();
expect(dom.window.document.body.textContent).toContain(
"redirect_uri_mismatch"
);
});
});