refactor(chat): centralize unlock coordination
This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import type {
|
||||
PendingChatPromotion,
|
||||
PendingChatUnlock,
|
||||
} from "@/lib/navigation/chat_unlock_session";
|
||||
import { createChatPromotionState } from "@/stores/chat/helper/promotion";
|
||||
|
||||
import {
|
||||
resolveChatUnlockReturnUrl,
|
||||
resolveMessageUnlockRequest,
|
||||
shouldResumePendingChatUnlock,
|
||||
} from "../hooks/use-chat-unlock-coordinator";
|
||||
|
||||
const defaultScope = {
|
||||
defaultReturnUrl: "/chat",
|
||||
imageMessageId: null,
|
||||
imageReturnUrl: "/chat",
|
||||
promotion: null,
|
||||
};
|
||||
|
||||
const promotionSession: PendingChatPromotion = {
|
||||
promotionType: "image",
|
||||
lockType: "image_paywall",
|
||||
clientLockId: "promotion-1",
|
||||
createdAt: 1,
|
||||
};
|
||||
|
||||
describe("chat unlock coordinator", () => {
|
||||
it("creates a regular message unlock request with its remote id", () => {
|
||||
expect(
|
||||
resolveMessageUnlockRequest(
|
||||
{ messageId: "message-1", kind: "private" },
|
||||
defaultScope,
|
||||
),
|
||||
).toEqual({
|
||||
displayMessageId: "message-1",
|
||||
messageId: "message-1",
|
||||
kind: "private",
|
||||
returnUrl: "/chat",
|
||||
});
|
||||
});
|
||||
|
||||
it("returns to the active image overlay for its image unlock", () => {
|
||||
const imageScope = {
|
||||
...defaultScope,
|
||||
imageMessageId: "image-1",
|
||||
imageReturnUrl: "/chat?image=image-1",
|
||||
};
|
||||
|
||||
expect(
|
||||
resolveMessageUnlockRequest(
|
||||
{ messageId: "image-1", kind: "image" },
|
||||
imageScope,
|
||||
).returnUrl,
|
||||
).toBe("/chat?image=image-1");
|
||||
});
|
||||
|
||||
it("uses the promotion lock identity without sending a temporary remote id", () => {
|
||||
const promotion = createChatPromotionState(promotionSession);
|
||||
|
||||
expect(
|
||||
resolveMessageUnlockRequest(
|
||||
{ messageId: "promotion:promotion-1", kind: "image" },
|
||||
{ ...defaultScope, promotion },
|
||||
),
|
||||
).toEqual({
|
||||
displayMessageId: "promotion:promotion-1",
|
||||
kind: "image",
|
||||
lockType: "image_paywall",
|
||||
clientLockId: "promotion-1",
|
||||
promotion: promotionSession,
|
||||
returnUrl: "/chat",
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps the backend id after a promotion receives one", () => {
|
||||
const promotion = createChatPromotionState(
|
||||
promotionSession,
|
||||
"promotion-message-1",
|
||||
);
|
||||
|
||||
expect(
|
||||
resolveMessageUnlockRequest(
|
||||
{ messageId: "promotion-message-1", kind: "image" },
|
||||
{ ...defaultScope, promotion },
|
||||
).messageId,
|
||||
).toBe("promotion-message-1");
|
||||
});
|
||||
|
||||
it("resumes pending unlocks for the default chat return", () => {
|
||||
expect(
|
||||
shouldResumePendingChatUnlock(
|
||||
createPendingUnlock({
|
||||
displayMessageId: "message-1",
|
||||
messageId: "message-1",
|
||||
kind: "private",
|
||||
returnUrl: "/chat",
|
||||
}),
|
||||
defaultScope,
|
||||
),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("only resumes an image return when its message matches the overlay", () => {
|
||||
const imageScope = {
|
||||
defaultReturnUrl: "/chat",
|
||||
imageMessageId: "image-1",
|
||||
imageReturnUrl: "/chat?image=image-1",
|
||||
};
|
||||
const pending = createPendingUnlock({
|
||||
displayMessageId: "image-1",
|
||||
messageId: "image-1",
|
||||
kind: "image",
|
||||
returnUrl: "/chat?image=image-1",
|
||||
});
|
||||
|
||||
expect(shouldResumePendingChatUnlock(pending, imageScope)).toBe(true);
|
||||
expect(
|
||||
shouldResumePendingChatUnlock(
|
||||
{ ...pending, displayMessageId: "image-2", messageId: "image-2" },
|
||||
imageScope,
|
||||
),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it("never routes a promotion unlock through the image overlay", () => {
|
||||
const promotion = createChatPromotionState(promotionSession);
|
||||
const imageMessageId = "promotion:promotion-1";
|
||||
const imageScope = {
|
||||
defaultReturnUrl: "/chat",
|
||||
imageMessageId,
|
||||
imageReturnUrl: `/chat?image=${imageMessageId}`,
|
||||
};
|
||||
|
||||
expect(
|
||||
resolveMessageUnlockRequest(
|
||||
{ messageId: imageMessageId, kind: "image" },
|
||||
{
|
||||
...imageScope,
|
||||
promotion,
|
||||
},
|
||||
).returnUrl,
|
||||
).toBe("/chat");
|
||||
expect(
|
||||
shouldResumePendingChatUnlock(
|
||||
{
|
||||
...createPendingUnlock({
|
||||
displayMessageId: imageMessageId,
|
||||
kind: "image",
|
||||
returnUrl: imageScope.imageReturnUrl,
|
||||
}),
|
||||
lockType: promotionSession.lockType,
|
||||
clientLockId: promotionSession.clientLockId,
|
||||
promotion: promotionSession,
|
||||
},
|
||||
imageScope,
|
||||
),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it("keeps a regular image paywall in the chat flow when no overlay is open", () => {
|
||||
expect(
|
||||
resolveChatUnlockReturnUrl(
|
||||
{
|
||||
displayMessageId: "image-1",
|
||||
messageId: "image-1",
|
||||
kind: "image",
|
||||
},
|
||||
defaultScope,
|
||||
),
|
||||
).toBe("/chat");
|
||||
});
|
||||
});
|
||||
|
||||
function createPendingUnlock(
|
||||
input: Pick<
|
||||
PendingChatUnlock,
|
||||
"displayMessageId" | "messageId" | "kind" | "returnUrl"
|
||||
>,
|
||||
): PendingChatUnlock {
|
||||
return {
|
||||
reason: "single_message_unlock",
|
||||
...input,
|
||||
stage: "auth",
|
||||
createdAt: 1,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user