196 lines
6.1 KiB
TypeScript
196 lines
6.1 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
import { buildGlobalPageUrl } from "@/router/global-route-context";
|
|
import { getCharacterRoutes, ROUTES } from "@/router/routes";
|
|
|
|
import { consumePendingChatImageReturn } from "../chat_image_return_session";
|
|
import {
|
|
clearPendingChatUnlock,
|
|
peekPendingChatUnlock,
|
|
} from "../chat_unlock_session";
|
|
import {
|
|
consumeSubscriptionExitUrl,
|
|
consumeSubscriptionExplicitExitUrl,
|
|
getSubscriptionFallbackExitUrl,
|
|
peekSubscriptionExplicitExitUrl,
|
|
resolveSubscriptionSuccessExitUrl,
|
|
} from "../subscription_exit";
|
|
|
|
vi.mock("../chat_image_return_session", () => ({
|
|
consumePendingChatImageReturn: vi.fn(),
|
|
}));
|
|
vi.mock("../chat_unlock_session", () => ({
|
|
clearPendingChatUnlock: vi.fn(),
|
|
peekPendingChatUnlock: vi.fn(),
|
|
}));
|
|
|
|
const consumePendingChatImageReturnMock = vi.mocked(
|
|
consumePendingChatImageReturn,
|
|
);
|
|
const clearPendingChatUnlockMock = vi.mocked(clearPendingChatUnlock);
|
|
const peekPendingChatUnlockMock = vi.mocked(peekPendingChatUnlock);
|
|
|
|
describe("subscription exit helpers", () => {
|
|
beforeEach(() => {
|
|
consumePendingChatImageReturnMock.mockReset();
|
|
clearPendingChatUnlockMock.mockReset();
|
|
peekPendingChatUnlockMock.mockReset();
|
|
});
|
|
|
|
it("uses explicit chat image return urls first", async () => {
|
|
consumePendingChatImageReturnMock.mockResolvedValue({
|
|
reason: "image_paywall",
|
|
characterId: "elio",
|
|
messageId: "msg_1",
|
|
returnUrl: "/chat?image=msg_1",
|
|
createdAt: 1,
|
|
});
|
|
|
|
await expect(consumeSubscriptionExplicitExitUrl()).resolves.toBe(
|
|
"/chat?image=msg_1",
|
|
);
|
|
});
|
|
|
|
it("falls back to chat when requested", async () => {
|
|
consumePendingChatImageReturnMock.mockResolvedValue(null);
|
|
peekPendingChatUnlockMock.mockResolvedValue(null);
|
|
|
|
await expect(consumeSubscriptionExitUrl("chat")).resolves.toBe(
|
|
getCharacterRoutes("elio").chat,
|
|
);
|
|
});
|
|
|
|
it("falls back to sidebar by default", async () => {
|
|
consumePendingChatImageReturnMock.mockResolvedValue(null);
|
|
peekPendingChatUnlockMock.mockResolvedValue(null);
|
|
|
|
expect(getSubscriptionFallbackExitUrl(null)).toBe(ROUTES.sidebar);
|
|
await expect(consumeSubscriptionExitUrl(null)).resolves.toBe(
|
|
ROUTES.sidebar,
|
|
);
|
|
});
|
|
|
|
it("returns to global sidebar with the source character", async () => {
|
|
const expectedUrl = buildGlobalPageUrl(
|
|
ROUTES.sidebar,
|
|
getCharacterRoutes("maya").chat,
|
|
);
|
|
|
|
expect(getSubscriptionFallbackExitUrl("sidebar", "maya")).toBe(
|
|
expectedUrl,
|
|
);
|
|
await expect(
|
|
consumeSubscriptionExitUrl("sidebar", "maya"),
|
|
).resolves.toBe(expectedUrl);
|
|
await expect(
|
|
resolveSubscriptionSuccessExitUrl("sidebar", "maya"),
|
|
).resolves.toBe(expectedUrl);
|
|
expect(consumePendingChatImageReturnMock).not.toHaveBeenCalled();
|
|
expect(peekPendingChatUnlockMock).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("returns directly to private room without consuming chat state", async () => {
|
|
consumePendingChatImageReturnMock.mockResolvedValue({
|
|
reason: "image_paywall",
|
|
characterId: "elio",
|
|
messageId: "msg_1",
|
|
returnUrl: "/chat?image=msg_1",
|
|
createdAt: 1,
|
|
});
|
|
peekPendingChatUnlockMock.mockResolvedValue({
|
|
reason: "single_message_unlock",
|
|
characterId: "elio",
|
|
displayMessageId: "msg_1",
|
|
messageId: "msg_1",
|
|
kind: "image",
|
|
returnUrl: "/chat?image=msg_1",
|
|
stage: "payment",
|
|
createdAt: 1,
|
|
});
|
|
|
|
expect(getSubscriptionFallbackExitUrl("private-room")).toBe(
|
|
getCharacterRoutes("elio").privateRoom,
|
|
);
|
|
await expect(consumeSubscriptionExitUrl("private-room")).resolves.toBe(
|
|
getCharacterRoutes("elio").privateRoom,
|
|
);
|
|
expect(consumePendingChatImageReturnMock).not.toHaveBeenCalled();
|
|
expect(peekPendingChatUnlockMock).not.toHaveBeenCalled();
|
|
expect(clearPendingChatUnlockMock).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("keeps private room ahead of stale chat state after payment", async () => {
|
|
peekPendingChatUnlockMock.mockResolvedValue({
|
|
reason: "single_message_unlock",
|
|
characterId: "elio",
|
|
displayMessageId: "msg_1",
|
|
messageId: "msg_1",
|
|
kind: "image",
|
|
returnUrl: "/chat?image=msg_1",
|
|
stage: "payment",
|
|
createdAt: 1,
|
|
});
|
|
|
|
await expect(
|
|
resolveSubscriptionSuccessExitUrl("private-room", "maya"),
|
|
).resolves.toBe(getCharacterRoutes("maya").privateRoom);
|
|
expect(peekPendingChatUnlockMock).not.toHaveBeenCalled();
|
|
expect(clearPendingChatUnlockMock).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("keeps pending chat unlocks ahead of chat fallback after payment", async () => {
|
|
peekPendingChatUnlockMock.mockResolvedValue({
|
|
reason: "single_message_unlock",
|
|
characterId: "elio",
|
|
displayMessageId: "msg_1",
|
|
messageId: "msg_1",
|
|
kind: "image",
|
|
returnUrl: "/chat?image=msg_1",
|
|
stage: "payment",
|
|
createdAt: 1,
|
|
});
|
|
|
|
await expect(resolveSubscriptionSuccessExitUrl("chat")).resolves.toBe(
|
|
"/chat?image=msg_1",
|
|
);
|
|
expect(clearPendingChatUnlockMock).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("peeks chat unlock return urls without clearing them", async () => {
|
|
peekPendingChatUnlockMock.mockResolvedValue({
|
|
reason: "single_message_unlock",
|
|
characterId: "elio",
|
|
displayMessageId: "msg_1",
|
|
messageId: "msg_1",
|
|
kind: "image",
|
|
returnUrl: "/chat?image=msg_1",
|
|
stage: "payment",
|
|
createdAt: 1,
|
|
});
|
|
|
|
await expect(peekSubscriptionExplicitExitUrl()).resolves.toBe(
|
|
"/chat?image=msg_1",
|
|
);
|
|
expect(clearPendingChatUnlockMock).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("clears chat unlock return urls when consumed", async () => {
|
|
consumePendingChatImageReturnMock.mockResolvedValue(null);
|
|
peekPendingChatUnlockMock.mockResolvedValue({
|
|
reason: "single_message_unlock",
|
|
characterId: "elio",
|
|
displayMessageId: "msg_1",
|
|
messageId: "msg_1",
|
|
kind: "image",
|
|
returnUrl: "/chat?image=msg_1",
|
|
stage: "payment",
|
|
createdAt: 1,
|
|
});
|
|
|
|
await expect(consumeSubscriptionExplicitExitUrl()).resolves.toBe(
|
|
"/chat?image=msg_1",
|
|
);
|
|
expect(clearPendingChatUnlockMock).toHaveBeenCalledTimes(1);
|
|
});
|
|
});
|