Files
cozsweet-frontend-nextjs/src/providers/__tests__/character-actor-scope-providers.test.tsx
T

190 lines
5.0 KiB
TypeScript

/* @vitest-environment jsdom */
import { act, type ReactNode } from "react";
import { createRoot, type Root } from "react-dom/client";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
const instances = vi.hoisted(() => ({
chat: 0,
payment: 0,
privateZone: 0,
}));
vi.mock("@/stores/chat/chat-context", async () => {
const { createElement, useState } = await import("react");
return {
ChatProvider({
characterId,
children,
}: {
characterId: string;
children: ReactNode;
}) {
const [instanceId] = useState(() => ++instances.chat);
return createElement(
"div",
{
"data-character-id": characterId,
"data-instance-id": instanceId,
"data-testid": "chat-provider",
},
children,
);
},
};
});
vi.mock("@/stores/payment/payment-context", async () => {
const { createElement, useState } = await import("react");
return {
PaymentProvider({ children }: { children: ReactNode }) {
const [instanceId] = useState(() => ++instances.payment);
return createElement(
"div",
{
"data-instance-id": instanceId,
"data-testid": "payment-provider",
},
children,
);
},
};
});
vi.mock("@/stores/private-zone", async () => {
const { createElement, useState } = await import("react");
return {
PrivateZoneProvider({
characterId,
children,
}: {
characterId: string;
children: ReactNode;
}) {
const [instanceId] = useState(() => ++instances.privateZone);
return createElement(
"div",
{
"data-character-id": characterId,
"data-instance-id": instanceId,
"data-testid": "private-zone-provider",
},
children,
);
},
};
});
vi.mock("@/stores/sync/chat-auth-sync", () => ({ ChatAuthSync: () => null }));
vi.mock("@/stores/sync/chat-payment-success-sync", () => ({
ChatPaymentSuccessSync: () => null,
}));
vi.mock("@/stores/sync/payment-success-sync", () => ({
PaymentSuccessSync: () => null,
}));
import { ChatRouteProviders } from "@/providers/chat-route-providers";
import { PaymentRouteProvider } from "@/providers/payment-route-provider";
import { PrivateZoneRouteProvider } from "@/providers/private-zone-route-provider";
describe("character actor route providers", () => {
let container: HTMLDivElement;
let root: Root;
beforeEach(() => {
instances.chat = 0;
instances.payment = 0;
instances.privateZone = 0;
(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean })
.IS_REACT_ACT_ENVIRONMENT = true;
container = document.createElement("div");
document.body.append(container);
root = createRoot(container);
});
afterEach(() => {
act(() => root.unmount());
container.remove();
});
it("recreates chat and chat payment actors when the character changes", () => {
renderChat("elio");
const firstChatInstance = instanceId("chat-provider");
const firstPaymentInstance = instanceId("payment-provider");
renderChat("maya-tan");
expect(instanceId("chat-provider")).not.toBe(firstChatInstance);
expect(instanceId("payment-provider")).not.toBe(firstPaymentInstance);
expect(testNode("chat-provider").dataset.characterId).toBe(
"maya-tan",
);
});
it("recreates the private-zone actor when the character changes", () => {
renderPrivateZone("elio");
const firstInstance = instanceId("private-zone-provider");
renderPrivateZone("maya-tan");
expect(instanceId("private-zone-provider")).not.toBe(firstInstance);
expect(testNode("private-zone-provider").dataset.characterId).toBe(
"maya-tan",
);
});
it("recreates the route payment actor when its character scope changes", () => {
renderPayment("elio");
const firstInstance = instanceId("payment-provider");
renderPayment("maya-tan");
expect(instanceId("payment-provider")).not.toBe(firstInstance);
});
function renderChat(characterId: string): void {
act(() => {
root.render(
<ChatRouteProviders
characterId={characterId}
emptyChatGreeting={`Hello from ${characterId}`}
>
<span>chat</span>
</ChatRouteProviders>,
);
});
}
function renderPrivateZone(characterId: string): void {
act(() => {
root.render(
<PrivateZoneRouteProvider characterId={characterId}>
<span>private zone</span>
</PrivateZoneRouteProvider>,
);
});
}
function renderPayment(scopeKey: string): void {
act(() => {
root.render(
<PaymentRouteProvider scopeKey={scopeKey}>
<span>payment</span>
</PaymentRouteProvider>,
);
});
}
function testNode(testId: string): HTMLElement {
const node = container.querySelector<HTMLElement>(
`[data-testid="${testId}"]`,
);
if (!node) throw new Error(`Missing ${testId}`);
return node;
}
function instanceId(testId: string): string | undefined {
return testNode(testId).dataset.instanceId;
}
});