refactor(private-zoom): rename full feature surface
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
/* @vitest-environment jsdom */
|
||||
|
||||
import { act } from "react";
|
||||
import { createRoot, type Root } from "react-dom/client";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import { PrivateAlbumSchema } from "@/data/schemas/private-zoom";
|
||||
|
||||
import { PrivateAlbumCard } from "../private-album-card";
|
||||
|
||||
describe("PrivateAlbumCard interactions", () => {
|
||||
let container: HTMLDivElement;
|
||||
let root: Root;
|
||||
|
||||
beforeEach(() => {
|
||||
(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("opens the selected thumbnail with its original source index", () => {
|
||||
const onOpenGallery = vi.fn();
|
||||
const album = PrivateAlbumSchema.parse({
|
||||
albumId: "album-1",
|
||||
title: "Private afternoon",
|
||||
imageCount: 4,
|
||||
images: [
|
||||
{ url: "", locked: false, index: 0 },
|
||||
{ url: "/images/private-zoom/locked.png", locked: true, index: 1 },
|
||||
{ url: "/images/private-zoom/photo-2.png", locked: false, index: 2 },
|
||||
{ url: "/images/private-zoom/photo-3.png", locked: false, index: 3 },
|
||||
],
|
||||
locked: false,
|
||||
unlocked: true,
|
||||
lockDetail: { locked: false },
|
||||
});
|
||||
|
||||
act(() => {
|
||||
root.render(
|
||||
<PrivateAlbumCard
|
||||
album={album}
|
||||
displayName="Elio Silvestri"
|
||||
avatarUrl="/images/avatar/elio.png"
|
||||
index={0}
|
||||
isUnlocking={false}
|
||||
onOpenGallery={onOpenGallery}
|
||||
onUnlock={() => undefined}
|
||||
/>,
|
||||
);
|
||||
});
|
||||
|
||||
const thumbnail = container.querySelector<HTMLButtonElement>(
|
||||
'button[data-image-index="3"]',
|
||||
);
|
||||
act(() => thumbnail?.click());
|
||||
|
||||
expect(onOpenGallery).toHaveBeenCalledOnce();
|
||||
expect(onOpenGallery).toHaveBeenCalledWith(3);
|
||||
});
|
||||
|
||||
it("unlocks only from the collection CTA and disables repeat actions", () => {
|
||||
const onUnlock = vi.fn();
|
||||
const album = PrivateAlbumSchema.parse({
|
||||
albumId: "album-locked",
|
||||
title: "Locked afternoon",
|
||||
imageCount: 3,
|
||||
images: [
|
||||
{ url: "/images/private-zoom/locked.png", locked: true, index: 0 },
|
||||
],
|
||||
locked: true,
|
||||
unlocked: false,
|
||||
unlockCost: 40,
|
||||
lockDetail: { locked: true },
|
||||
});
|
||||
|
||||
renderLockedCard(album, false, onUnlock);
|
||||
const avatar = container.querySelector<HTMLElement>(
|
||||
'[aria-label="Elio Silvestri locked collection"]',
|
||||
);
|
||||
act(() => avatar?.parentElement?.click());
|
||||
expect(onUnlock).not.toHaveBeenCalled();
|
||||
|
||||
const button = findCollectionButton();
|
||||
act(() => button.click());
|
||||
expect(onUnlock).toHaveBeenCalledOnce();
|
||||
|
||||
renderLockedCard(album, true, onUnlock);
|
||||
const disabledButton = findCollectionButton();
|
||||
expect(disabledButton.disabled).toBe(true);
|
||||
expect(disabledButton.textContent).toBe("Opening...");
|
||||
act(() => disabledButton.click());
|
||||
expect(onUnlock).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
function renderLockedCard(
|
||||
album: ReturnType<typeof PrivateAlbumSchema.parse>,
|
||||
isUnlocking: boolean,
|
||||
onUnlock: () => void,
|
||||
): void {
|
||||
act(() => {
|
||||
root.render(
|
||||
<PrivateAlbumCard
|
||||
album={album}
|
||||
displayName="Elio Silvestri"
|
||||
avatarUrl="/images/avatar/elio.png"
|
||||
index={0}
|
||||
isUnlocking={isUnlocking}
|
||||
onOpenGallery={() => undefined}
|
||||
onUnlock={onUnlock}
|
||||
/>,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function findCollectionButton(): HTMLButtonElement {
|
||||
const button = Array.from(container.querySelectorAll("button")).find(
|
||||
(item) =>
|
||||
item.textContent === "View collection" ||
|
||||
item.textContent === "Opening...",
|
||||
);
|
||||
if (!button) throw new Error("Missing View collection button");
|
||||
return button;
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user